Deno 2 で npm パッケージが動かない・import エラーになる時の原因と対処法【npm: specifier / node: 組み込みモジュール】
公開日:2026-09-15/カテゴリ:Deno・Node.js・TypeScript/AnchorUp 技術ブログ
Deno 2 で npm パッケージが動かない症状
Deno 2 にアップグレードしたとき、または Node.js プロジェクトを Deno に移行しようとしたとき、こんなエラーに遭遇したことはないですか?
error: Module not found "express".
error: Cannot find module 'fs'
error: Relative import path "lodash" not prefixed with / or ./
Deno はブラウザ互換の ESモジュールを採用しており、Node.js とはモジュール解決の仕組みが根本的に異なります。この違いを理解すれば、ほとんどのエラーは数分で解決できます。
原因一覧
| 症状 | 原因 | 対処法 |
|---|---|---|
Module not found "express" |
npm: プレフィックスがない |
npm:express と書く |
Cannot find module 'fs' |
node: プレフィックスがない |
node:fs と書く |
| CJS モジュールが動かない | CommonJS 専用パッケージ | 互換パッケージを探す or ワークアラウンド |
PermissionDenied エラー |
Deno のパーミッション制限 | --allow-* フラグを追加 |
| ネイティブアドオンがクラッシュ | N-API バインディング非対応 | 代替パッケージを使う |
なぜ Deno は Node.js と import の書き方が違うのか
Deno は設計上「URL や明示的なパスでのインポート」を原則としています。Node.js の require('express') のような「ベア(bare)スペシファイアー」でのインポートは、Deno にとってはデフォルトでは意味を持ちません。
Deno 2 では Node.js との互換性が大幅に強化されましたが、明示的に「このモジュールは npm から取得する」「これは Node.js 組み込みモジュールだ」と宣言する必要があります。それが npm: と node: というプレフィックスです。
対処法1:npm: プレフィックスを使う
npm パッケージには必ず npm: プレフィックスを付けてください。
// ❌ 動かない(Node.js のベアスペシファイアー)
import express from 'express'
import _ from 'lodash'
import { z } from 'zod'
// ✅ 動く(Deno の npm: スペシファイアー)
import express from 'npm:express@4'
import _ from 'npm:lodash'
import { z } from 'npm:zod'
バージョンは省略可能ですが、再現性のためにピン留めすることを推奨します。
// バージョン指定あり(推奨)
import { Hono } from 'npm:hono@4'
import { drizzle } from 'npm:drizzle-orm@0.36.0/node-postgres'
対処法2:node: プレフィックスで組み込みモジュールを使う
Node.js 組み込みモジュール(fs、path、crypto 等)は node: プレフィックスが必要です。
// ❌ 動かない
import { readFileSync } from 'fs'
import path from 'path'
import { createHash } from 'crypto'
// ✅ 動く
import { readFileSync } from 'node:fs'
import path from 'node:path'
import { createHash } from 'node:crypto'
node: プレフィックスなしのベアスペシファイアーは、deno.json で nodeModulesDir を設定すれば使えるようになります(後述)。
対処法3:package.json を使ってベアスペシファイアーを有効にする
既存の Node.js プロジェクトをそのまま Deno で動かしたい場合は、package.json と deno.json を組み合わせる方法が有効です。
deno.json の設定:
{
"nodeModulesDir": "auto"
}
"nodeModulesDir": "auto" を設定すると、package.json の dependencies を読んで node_modules/ を生成するため、ベアスペシファイアーがそのまま動きます。
deno install # node_modules を生成
deno run main.ts
これにより、既存の Node.js コードを大幅に変更せずに Deno で実行できます。
対処法4:import map でエイリアスを設定する
deno.json の imports セクションでエイリアスを定義すれば、ファイルの先頭をすっきりさせられます。
{
"imports": {
"express": "npm:express@4",
"lodash": "npm:lodash",
"zod": "npm:zod",
"fs": "node:fs",
"path": "node:path"
}
}
// deno.json の imports を使えばプレフィックスなしで書ける
import express from 'express'
import { z } from 'zod'
import { readFileSync } from 'fs'
大規模なプロジェクトではこの方法が最もメンテナンスしやすいです。
対処法5:パーミッションエラーへの対応
Deno はセキュリティファーストな設計のため、ファイルシステム・ネットワーク・環境変数へのアクセスには明示的なパーミッションが必要です。
Uncaught PermissionDenied: Requires net access to "api.example.com"
# 必要なパーミッションを指定して実行
deno run --allow-net --allow-read --allow-env main.ts
# 開発中は全パーミッションを許可する(本番は非推奨)
deno run --allow-all main.ts
| フラグ | 許可する操作 |
|---|---|
--allow-net |
ネットワークアクセス |
--allow-read |
ファイル読み取り |
--allow-write |
ファイル書き込み |
--allow-env |
環境変数へのアクセス |
--allow-run |
サブプロセスの実行 |
--allow-all |
全パーミッション(-A でも可) |
CommonJS 専用パッケージが動かない場合
一部の古い npm パッケージは CommonJS 形式のみで提供されており、Deno との互換性に問題が生じることがあります。
error: Cannot load CJS module "some-package"
対処法:
- ESM 版があるか確認する:
"some-package/esm"や"some-package-esm"のような ESM ビルドを探す npm:some-packageで試す:Deno の npm サポートは CJS を自動変換する場合がある- 代替パッケージを使う:例えば
momentの代わりにnpm:dayjs(ESM 対応)を使う
よくある環境変数まわりのエラー
Node.js では process.env.API_KEY が一般的ですが、Deno では Deno.env.get('API_KEY') が推奨されます。ただし process.env も Deno 2 ではサポートされています。
// Deno ネイティブな書き方
const apiKey = Deno.env.get('API_KEY')
// Node.js 互換の書き方(Deno 2 でも動く)
const apiKey = process.env.API_KEY
--allow-env を渡し忘れると PermissionDenied になるので注意してください。
まとめ
| 問題 | 解決策 |
|---|---|
| npm パッケージが見つからない | npm:パッケージ名 プレフィックスを付ける |
| Node.js 組み込みが動かない | node:fs のように node: を付ける |
| ベアスペシファイアーをそのまま使いたい | deno.json で "nodeModulesDir": "auto" + deno install |
| プレフィックスなしで書きたい | deno.json の imports でエイリアスを設定 |
| パーミッションエラー | --allow-net 等のフラグを追加 |
Deno 2 は Node.js との互換性を大幅に改善しており、既存の npm エコシステムをほぼそのまま使えます。「npm: と node: プレフィックス」という基本ルールを押さえれば、移行コストは想像より低いはずです。
既存プロジェクトの移行には "nodeModulesDir": "auto" から始めて、徐々に Deno ネイティブな書き方に移行するのがスムーズです。