---
title: "AdonisJSとは？v7のインストールからCRUD API・Inertia連携、脆弱性対応まで実行して解説"
url: "https://www.issoh.co.jp/tech/details/7000/"
published: 2025-05-28
updated: 2026-11-05
categories: ["Node.js"]
publisher: "株式会社一創"
---

# AdonisJSとは？v7のインストールからCRUD API・Inertia連携、脆弱性対応まで実行して解説

AdonisJS（アドニスJS）は、TypeScriptで書くNode.js向けのフルスタックフレームワークです。ルーティング、ORM、バリデーション、認証、テストランナーを公式パッケージとして同梱し、LaravelやRuby on Railsに近い「決まった置き場所に書けば動く」開発体験をNode.jsで提供します。現行はv7系で、v7.0.0は2026年2月25日に公開されました。2026年11月5日時点のnpm最新は、2026年10月5日公開の [@adonisjs/core 7.6.0](https://github.com/adonisjs/core/releases/tag/v7.6.0) です。

この記事では、v7のプロジェクトを実際に作成し、CRUD APIを組んでcurlで叩いた結果をもとに、インストール手順、ディレクトリ構成、Lucid ORMとVineJSの書き方、Inertia連携、v6からの変更点、2026年11月4日に公開された脆弱性の確認手順を順に説明します。検証環境はmacOS（Intel）上のNode.js v26.5.0、npm 11.17.0です（CRUDは2026年9月28日に core 7.5.2 で、版と脆弱性まわりは2026年11月5日に core 7.6.0 で確認）。

## まとめ：AdonisJS v7の要点

- AdonisJSはTypeScript前提の「全部入り」Node.jsフレームワーク。ライセンスはMITで、GitHubの adonisjs/core は19,171スター（2026年11月5日時点）。
- 現行はv7系。**Node.js 24以上が必須**で、@adonisjs/core 7.6.0 の engines も `>=24.0.0` です。
- 新規作成は `npm init adonisjs@latest`。スターターキットは hypermedia／react／vue／api／api-monorepo の5種で、どれもLucid ORMと認証（ログイン・サインアップ）が最初から入ります。
- v7ではマイグレーションからモデルの列定義（`database/schema.ts`）が自動生成され、レスポンス整形はTransformer、ルートのコントローラー参照は自動生成のバレルファイル経由になりました。
- 旧来の `npm i -g @adonisjs/cli` と `adonis new` はv4時代のもので、現行プロジェクトでは使いません。
- 実装上の落とし穴として、Lucid 22.4.2 の `make:model --controller` はコントローラーを作らず（core 7.6.0でも同じ）、SQLiteでは真偽値が1・0で返ります。対処は本文で示します。
- **2026年11月4日に、multipart処理の脆弱性2件（認証不要のDoS）が公開**されました。v7は @adonisjs/bodyparser 11.0.5、v6は10.1.6で修正済みです。既存プロジェクトはロックファイルに古い版が残るため、`npm update @adonisjs/bodyparser` で上げます。

既存アプリの保守担当者は脆弱性対応、新規導入を試す方はインストール手順から確認してください。

## AdonisJSの位置づけ：Express・NestJS・Laravelとの比較

### Express・NestJSとの同梱範囲の違い

Node.jsのWebフレームワークは、何を同梱するかで性格が分かれます。[Express.js](/tech/details/3857/)はルーティングとミドルウェアの仕組みだけを持ち、ORMやバリデーションは自分で選んで組み合わせます。NestJSはDIとモジュール構造を提供しますが、ORMはTypeORMやPrismaなど外部から選ぶ前提です。AdonisJSはORM（Lucid）、バリデーション（VineJS）、認証、セッション、テスト（Japa）まで公式パッケージで揃え、生成コマンド（ace）で決まった場所にファイルを作ります。

| 項目      | AdonisJS v7        | NestJS                | Express 5        |
| ------- | ------------------ | --------------------- | ---------------- |
| 言語      | TypeScript前提       | TypeScript／JavaScript | JavaScript（型は任意） |
| ORM     | Lucid（公式）          | 外部から選択                | 外部から選択           |
| バリデーション | VineJS（公式）         | class-validator等      | 外部から選択           |
| 認証      | @adonisjs/auth（公式） | Passport等             | 外部から選択           |
| テンプレート  | Edge／Inertia       | 外部から選択                | 外部から選択           |
| CLI生成   | node ace make:\*   | nest generate         | なし               |

AdonisJSはMVCの分け方（Model＝Lucidモデル、View＝EdgeまたはInertia、Controller＝app/controllers）をそのまま採っています。部品を選ぶ自由より、構成を議論しなくて済むことを優先するフレームワークです。NestJSのDTOとValidationPipeの考え方は[DTOとNestJSのValidationPipe設定](/tech/details/6208/)で扱っています。

### Laravel・Ruby on Railsとの対応表

LaravelやRailsの経験者は、どのファイルとコマンドが何に当たるかを先に押さえると早く読めます。名前が違うだけで、ルート→コントローラー→モデル→マイグレーションの分担は3つとも同じです。

| 役割         | AdonisJS v7            | Laravel         | Ruby on Rails       |
| ---------- | ---------------------- | --------------- | ------------------- |
| ルート定義      | start/routes.ts        | routes/web.php  | config/routes.rb    |
| CLI        | node ace               | php artisan     | bin/rails           |
| コントローラー生成  | make:controller        | make:controller | generate controller |
| ORM        | Lucid                  | Eloquent        | Active Record       |
| マイグレーション実行 | migration:run          | migrate         | db:migrate          |
| 入力検証       | VineJS（app/validators） | FormRequest     | モデルの validates      |
| テンプレート     | Edge                   | Blade           | ERB                 |
| JSONの整形    | Transformer            | API Resource    | Jbuilder等           |

大きく違うのはモデルの列定義です。v7はマイグレーション実行後にデータベースを走査して `database/schema.ts` を自動生成し、モデルはそれを継承します。列が生成済みのTypeScriptの型として並ぶため、モデルに無いプロパティへのアクセスは型チェックで検出できます。ただし `where('nonexistent_column', 1)` のようにクエリビルダーへ文字列で渡す列名までは検査されません。LaravelでAPIを組む流れは[Laravel APIの作り方](/tech/details/17137/)で解説しているので、手順を見比べると対応がつかみやすくなります。

## v7（2026年2月25日公開）で変わった点

公式ブログはv7を「破壊的変更を抑えたv6からの段階的アップグレード」と説明し、公式パッケージ45以上を更新して @adonisjs/otel・@adonisjs/content・edge-markdown の3つを新設しました。書き方に直接影響する変更は次のとおりです。

| 項目            | v6            | v7                             |
| ------------- | ------------- | ------------------------------ |
| Node.js       | 20以上          | 24以上                           |
| TypeScript実行  | ts-node       | @poppinss/ts-exec（SWCベース）      |
| モデルの列定義       | @column を手書き  | database/schema.ts を自動生成       |
| レスポンス整形       | モデルを暗黙にシリアライズ | Transformerで明示                 |
| ルートのコントローラー参照 | 動的importを列挙   | #generated/controllers のバレル    |
| 新規作成時の構成      | 対話でパッケージを選択   | 認証込みのスターターキット                  |
| 暗号化           | 単一設定          | 名前付きドライバ（config/encryption.ts） |

v6のプロジェクトを上げる場合は、公式の「v6 to v7」アップグレードガイドが手順を15段階（全パッケージ更新、ts-nodeからts-execへの置き換え、adonisrc.tsのフック設定、暗号化設定、`router.makeUrl` の置き換え、Request／Responseクラスの改名、Inertia連携の書き換えなど）に分けています。まずNode.js 24へ上げ、CIと本番サーバーのNode.jsも揃えてから着手してください。v6のドキュメントは v6-docs.adonisjs.com に残っています。v7の開発中に見つかったセキュリティ問題の修正はv6にもバックポートされ、次の章で扱う2026年11月の修正もv6向けに10.1.6が出ています。ただし、v6の保守終了日は2026年11月5日時点で公式に示されていません。

## 2026年11月4日公開のbodyparser脆弱性：既存プロジェクトの確認と更新手順

2026年11月4日、AdonisJSのリクエスト本文を解析する @adonisjs/bodyparser について、深刻度High（CVSS 7.5）の勧告が2件公開されました。どちらも `multipart/form-data` のリクエスト1件で、認証なしにサーバーを止められる問題です。bodyparserは既定でmultipartを解析するため、ファイルアップロードのルートを作っていないアプリも対象になります。

| 勧告                  | 起きること                      | 修正版（v7／v6）    |
| ------------------- | -------------------------- | ------------- |
| GHSA-8w45-cghr-9rh4 | パート名 \_\_proto\_\_ 等で例外・停止 | 11.0.5／10.1.6 |
| GHSA-jf2h-r4qp-9rp8 | ReDoS・メモリ枯渇・500応答          | 11.0.5／10.1.6 |

1件目の[GHSA-8w45-cghr-9rh4](https://github.com/adonisjs/core/security/advisories/GHSA-8w45-cghr-9rh4)は、ファイルパートの名前を `__proto__` や `constructor` にすると、ハンドラーの検索が `Object.prototype` から継承したメンバーを拾い、try/catchの外で `TypeError` が起きるものです。未処理のPromise拒否でワーカーが落ちるか、リクエストが応答しないまま残ります。回避策は無く、更新するしかありません。

2件目の[GHSA-jf2h-r4qp-9rp8](https://github.com/adonisjs/core/security/advisories/GHSA-jf2h-r4qp-9rp8)は、bodyparserが使うフォーク版の @poppinss/multiparty に、上流 multiparty 4.3.0・4.3.1 のセキュリティ修正が入っていなかった問題です。勧告の検証では、約1MBのリクエスト1件で `Content-Disposition` のファイル名解析がイベントループを約20秒止めました。パートヘッダーにはサイズの上限が無く、multipartの `limit` 設定も効かないため、送られた分だけメモリが増えます。修正は @poppinss/multiparty 3.0.1 に入っています。

### ロックファイルに古い版が残る理由と更新コマンド

@adonisjs/core 7.6.0 は bodyparser を `^11.0.4` の範囲で要求します。修正前の11.0.4もこの範囲に入るので、既存の package-lock.json に11.0.4が記録されていれば、`npm install` を実行しても入れ替わりません。11.0.4を記録したロックファイルを作って確かめたところ、`npm install` 後も11.0.4のままで、次のコマンドで11.0.5に上がりました。

```
npm ls @adonisjs/bodyparser @poppinss/multiparty   # 現在の版を確認
npm update @adonisjs/bodyparser                     # 11.0.5（v6なら10.1.6）へ更新
npm ls @adonisjs/bodyparser @poppinss/multiparty   # bodyparser 11.0.5・multiparty 3.0.1 を確認
```

2026年11月5日に `npx create-adonisjs@latest` で新しく作ったプロジェクトには、最初から11.0.5と3.0.1が入っていました。気をつけたいのは `npm audit` です。同じ日に11.0.4のプロジェクトで実行しても、今回の2件は出ませんでした（highは0件。出たのは minimatch 経由のmoderate 27件と deepmerge のlow 1件で、11.0.5のプロジェクトと同じ結果）。2件はadonisjs/coreリポジトリの勧告として公開されたもので、GitHubの全体の勧告データベースにはまだ載っていません。auditが通っても、`npm ls` で版を直接見てください。ロックファイルと更新コマンドの仕組みは[npmとは？CLIとレジストリの役割](/tech/details/17664/)で扱っています。

### 2026年に公開されたAdonisJS関連の勧告

bodyparserのmultipart処理は、2026年に入ってから繰り返し修正されています。長く運用するアプリでは、デプロイのたびにbodyparserとLucidの版を確認する手順をCIに入れておくべきです。

| 公開日        | 識別子                 | 内容                            | v7系の修正版                            |
| ---------- | ------------------- | ----------------------------- | ---------------------------------- |
| 2026-01-02 | CVE-2026-21440      | アップロードのパストラバーサル               | bodyparser 11.0.0-next.6           |
| 2026-01-13 | CVE-2026-22814      | Lucidの一括代入                    | lucid 22.0.0-next.6                |
| 2026-02-06 | CVE-2026-25754      | multipartのプロトタイプ汚染            | bodyparser 11.0.0-next.9           |
| 2026-02-06 | CVE-2026-25762      | multipartのメモリ無制限消費            | bodyparser 11.0.0-next.9           |
| 2026-04-14 | CVE-2026-40255      | redirect().back() のオープンリダイレクト | http-server 8.2.0（core 7.4.0以降を推奨） |
| 2026-05-28 | CVE-2026-48795      | CVE-2026-25754の修正漏れ           | bodyparser 11.0.3                  |
| 2026-11-04 | GHSA-8w45／GHSA-jf2h | multipartのDoS（上記2件）           | bodyparser 11.0.5                  |

上の4件はv7の正式公開前に修正済みで、v7.0.0以降なら影響しません。[公式のv7公開記事](https://adonisjs.com/blog/v7)も、開発期間中に4件のCVEを修正し、v6にもバックポートしたと説明しています。CVE-2026-48795は、プロトタイプ汚染の修正が `user.__proto__.polluted` のように手前に別の名前を挟んだ入力で迂回できた問題です。

## インストール手順：npm init adonisjsとスターターキット5種

### Node.js 24以上の確認と作成コマンド

最初に `node -v` で24以上であることを確かめます。Node.jsの版の選び方は[Node.jsとは？仕組み・版の選び方](/tech/details/17433/)を参照してください。作成コマンドは次の1行で、対話形式でキットを選びます。

```
npm init adonisjs@latest my-app
```

CIやスクリプトなど対話できない環境では、キットとパッケージマネージャーをフラグで渡します（create-adonisjs 3.4.0 で確認）。非対話環境でフラグを省くと、キット一覧を示して終了します。

```
npx create-adonisjs@latest my-api --kit=api --pkg=npm
```

上記の検証環境では、この1コマンドでダウンロード、依存パッケージのインストール、アプリの準備、SQLiteへのマイグレーション実行まで進み、全体で1分4秒（9月28日）と3分1秒（11月5日）かかりました。差のほとんどは依存パッケージのダウンロード時間です。マイグレーションを後回しにしたい場合は `--skip-migrations` を付けます。

### 5種類のスターターキットと選び方

create-adonisjs 3.4.0 に定義されているキットは次の5種です（v7公開時のブログが紹介しているのは hypermedia・api・react・vue の4種）。

| `--kit` の値   | 用途                   | 認証         |
| ------------ | -------------------- | ---------- |
| hypermedia   | Edgeテンプレートのサーバー描画    | セッション＋CSRF |
| react        | Inertia＋React 19のSPA | セッション      |
| vue          | Inertia＋VueのSPA      | セッション      |
| api          | JSONを返すREST API      | アクセストークン   |
| api-monorepo | API＋フロントのモノレポ        | アクセストークン   |

選び方は単純です。画面をサーバーで描くならhypermedia、ReactかVueで画面を書きたいが別途APIを設計したくないならreact／vue、スマホアプリや別リポジトリのフロントに返すならapiを選びます。外部システムとつなぐAPIを設計段階から相談したい場合は、一創の[API開発・システム連携](/service/system/api/)でも支援しています。

### 旧CLI（adonis new）を使わない理由

古い解説記事にある `npm i -g @adonisjs/cli` と `adonis new` は、v4時代の手順です。npmレジストリの公開記録では、@adonisjs/cli が最後に公開されたのは2021年3月30日の4.0.13（latestタグ）です。現行のv6・v7では、プロジェクト作成は `npm init adonisjs`、以降の操作はプロジェクト内の `node ace` で行います。グローバルインストールは不要です。

## 生成されるディレクトリ構成と各ファイルの役割

apiキットで作成した直後の主要ファイルは次のとおりです（node\_modules等を除く）。

```
my-api/
├── adonisrc.ts            # プロバイダ・コマンド・フックの登録
├── ace.js                 # node ace の入口
├── app/
│   ├── controllers/       # access_tokens／new_account／profile
│   ├── middleware/        # auth_middleware など
│   ├── models/user.ts
│   ├── transformers/user_transformer.ts
│   └── validators/user.ts
├── bin/server.ts           # HTTPサーバーの起動
├── config/                # app・auth・database・cors・encryption など
├── database/
│   ├── migrations/
│   ├── schema.ts           # 自動生成（手で編集しない）
│   └── schema_rules.ts     # 生成ルールの上書き
├── start/
│   ├── routes.ts           # ルート定義
│   ├── kernel.ts           # ミドルウェアの登録
│   └── env.ts              # 環境変数のスキーマ
├── tests/bootstrap.ts      # Japa の設定
└── .adonisjs/             # 自動生成（controllers.ts・APIクライアント型）
```

古い記事にある `start/app.js` はv4の構成です。一方 `resources/` はv7でも hypermedia キットに含まれ、Edgeテンプレート（resources/views）の置き場所として使われます。apiキットには無いだけです。v7で手を入れるのは主に app・database/migrations・start/routes.ts の3か所で、`database/schema.ts` と `.adonisjs/` 配下は自動生成なので編集しません。package.json の `imports` に `#models/*` や `#controllers/*` などのサブパスが定義され、相対パスを書かずにimportできます。自動生成ファイルは開発サーバーの起動時に更新されますが、core 7.5.0（2026年8月21日）で追加された `node ace codegen` を使えば、サーバーを起動せずに再生成できます。CIで型チェックの前に実行する用途に向きます。

## CRUD APIを作る手順：モデル・マイグレーション・コントローラー

ここからはapiキットに投稿（Post）のCRUDを追加します。以降の `node ace` はすべて作成したプロジェクトのディレクトリ（`cd my-api` で移動した先）で実行します。コードはすべて冒頭の検証環境で動作を確認したものです。

### make:modelとmigration:runによるスキーマクラスの生成

モデルとマイグレーションを同時に作ります。

```
node ace make:model Post --migration --transformer
```

生成されたマイグレーションに列を足します。

```
import { BaseSchema } from '@adonisjs/lucid/schema'

export default class extends BaseSchema {
  protected tableName = 'posts'

  async up() {
    this.schema.createTable(this.tableName, (table) => {
      table.increments('id')
      table.string('title', 120).notNullable()
      table.text('body').notNullable()
      table.boolean('is_published').notNullable().defaultTo(false)
      table.timestamp('created_at')
      table.timestamp('updated_at')
    })
  }

  async down() {
    this.schema.dropTable(this.tableName)
  }
}
```

`node ace migration:run` を実行すると、テーブル作成に続いてデータベースを走査し、`database/schema.ts` に `PostSchema` クラスが書き出されます。snake\_caseの列はcamelCaseのプロパティ（`is_published` → `isPublished`）になり、`created_at` には `autoCreate` が付きます。モデル側は生成されたクラスを継承するだけです。

```
import { PostSchema } from '#database/schema'

export default class Post extends PostSchema {}
```

v6までのように、マイグレーションと同じ列をモデルの `@column` で書き直す必要はなくなりました。

### make:model `--controller` でコントローラーが生成されない不具合（Lucid 22.4.2）

ヘルプには `-c, --controller` と `-c, --transformer` が並んでおり、短縮形 `-c` が重複しています。@adonisjs/lucid 22.4.2 のソース（build/commands/make\_model.js）でも両フラグに `alias: 'c'` が付いていました。実際に `node ace make:model Tag --controller` を実行すると、作られたのはモデルとTransformerで、コントローラーは生成されませんでした。2026年11月5日に core 7.6.0 の新規プロジェクトで `node ace make:model Post --controller` を実行し直しても、作られたのは app/models/post.ts と app/transformers/post\_transformer.ts だけでした（Lucidは22.4.2から更新されていません）。コントローラーは別コマンドで作ります。

```
node ace make:controller posts --api
```

`--api` は create・edit（フォーム表示用）を除いた index・store・show・update・destroy の5メソッドを生成します。

### VineJSのバリデーションと422応答

バリデーターは `app/validators/post.ts` として保存します（コントローラーの `#validators/post` がこのファイルを指します）。v7のスターターキットは `vine.create` で書かれています（`vine.compile` もVineJS 4.4.0に残っています）。

```
import vine from '@vinejs/vine'

export const createPostValidator = vine.create({
  title: vine.string().trim().minLength(3).maxLength(120),
  body: vine.string().trim().minLength(1),
  isPublished: vine.boolean().optional(),
})

export const updatePostValidator = vine.create({
  title: vine.string().trim().minLength(3).maxLength(120).optional(),
  body: vine.string().trim().minLength(1).optional(),
  isPublished: vine.boolean().optional(),
})
```

コントローラー内の `request.validateUsing` で検証に失敗すると例外が投げられ、後続の保存処理は実行されずに422が返ります。titleを1文字・bodyを空で送った結果は次のとおりで、エラーは項目ごとの配列になります。

```
{"errors":[{"message":"The title field must have at least 3 characters","rule":"minLength","field":"title","meta":{"min":3}},{"message":"The body field must be defined","rule":"required","field":"body"}]}
```

空文字の `body` が `required` 違反になるのは、VineJS自体の挙動ではなく、キットの `config/bodyparser.ts` で `convertEmptyStringsToNull: true` が有効になっており、空文字が検証前に `null` へ変換されるためです。スターターキットの `signupValidator` でも、`fullName` は `nullable()` で定義されており、キーを省くと422になり、`null` を明示して送ると通りました。キー自体を省略可能にしたい項目には `optional()` を付けます。

### コントローラーとTransformerによるレスポンス整形

v7ではモデルをそのまま返さず、Transformerで公開する項目を選びます。`make:model` で作られたTransformerは `id` だけを返す雛形なので、項目を足します。

```
import { BaseTransformer } from '@adonisjs/core/transformers'
import Post from '#models/post'

export default class PostTransformer extends BaseTransformer<Post> {
  toObject() {
    return this.pick(this.resource, ['id', 'title', 'body', 'isPublished', 'createdAt'])
  }
}
```

コントローラーは、検証→保存→Transformerで整形、の流れで書きます。

```
import Post from '#models/post'
import PostTransformer from '#transformers/post_transformer'
import { createPostValidator, updatePostValidator } from '#validators/post'
import type { HttpContext } from '@adonisjs/core/http'

export default class PostsController {
  async index({ serialize }: HttpContext) {
    const posts = await Post.query().orderBy('id', 'desc')
    return serialize(PostTransformer.transform(posts))
  }

  async store({ request, response, serialize }: HttpContext) {
    const payload = await request.validateUsing(createPostValidator)
    const post = await Post.create(payload)
    response.status(201)
    return serialize(PostTransformer.transform(post))
  }

  async show({ params, serialize }: HttpContext) {
    const post = await Post.findOrFail(params.id)
    return serialize(PostTransformer.transform(post))
  }

  async update({ params, request, serialize }: HttpContext) {
    const post = await Post.findOrFail(params.id)
    const payload = await request.validateUsing(updatePostValidator)
    await post.merge(payload).save()
    return serialize(PostTransformer.transform(post))
  }

  async destroy({ params, response }: HttpContext) {
    const post = await Post.findOrFail(params.id)
    await post.delete()
    return response.noContent()
  }
}
```

`findOrFail` は該当行が無いと `E_ROW_NOT_FOUND` を投げ、フレームワークが404に変換します。開発環境（NODE\_ENV=development）ではこの404応答にスタックトレースが含まれるので、本番で `NODE_ENV=production` になっているかをデプロイ時に確かめてください。

### ルーティングとcurlでの動作確認

`start/routes.ts` の `/api/v1` グループに1行足します。`controllers` は自動生成のバレルファイルで、開発サーバーの起動時に `Posts` が追記されます。

```
import router from '@adonisjs/core/services/router'
import { controllers } from '#generated/controllers'

router
  .group(() => {
    // auth・account のルートはキットの既定のまま
    router.resource('posts', controllers.Posts).apiOnly()
  })
  .prefix('/api/v1')
```

`npm run dev`（中身は `node ace serve --hmr`）で起動し、3333番ポートに対してcurlで確認しました。作成リクエストは次の形です。`Accept: application/json` を付けると、検証エラーや404もJSONで返ります。

```
curl -i -X POST http://localhost:3333/api/v1/posts \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  --data '{"title":"First post","body":"Hello","isPublished":true}'
```

各リクエストの応答は次の表のとおりです。2026年11月5日に core 7.6.0 で、後述の「書き込みだけ認証必須」の構成にしてトークンを付けて送り直しても、投稿APIの6行は同じステータスでした。

| リクエスト                               | ステータス |
| ----------------------------------- | ----- |
| POST /api/v1/posts（正しい値）            | 201   |
| POST /api/v1/posts（titleが1文字）       | 422   |
| GET /api/v1/posts                   | 200   |
| PUT /api/v1/posts/1                 | 200   |
| GET /api/v1/posts/99（存在しない）         | 404   |
| DELETE /api/v1/posts/1              | 204   |
| GET /api/v1/account/profile（トークンなし） | 401   |

最後の行はapiキットに同梱された認証の動きです。`/api/v1/auth/signup` と `/api/v1/auth/login` がアクセストークンを返し、`middleware.auth()` を付けたルートはトークンが無いと401になります。投稿APIの書き込みだけを認証必須にする場合は、先ほどの `router.resource` の行を次のように置き換え、アクションを指定してミドルウェアを付けます。この形でトークンなしのPOSTが401、サインアップで得たトークンを `Authorization: Bearer` で付けたPOSTが201になることを確かめました。トークンはサインアップ応答の `data.token`（`oat_` で始まる文字列）に入っています。これは「ログインしているか」の確認だけで、他人の投稿を更新・削除できないようにする所有者チェック（認可）は含みません。必要なら @adonisjs/bouncer のポリシーなどで別途実装します。

```
router
  .resource('posts', controllers.Posts)
  .apiOnly()
  .use(['store', 'update', 'destroy'], middleware.auth())
```

```
curl -X POST http://localhost:3333/api/v1/auth/signup \
  -H 'Content-Type: application/json' -H 'Accept: application/json' \
  --data '{"fullName":"Hanako","email":"hanako@example.com","password":"secret-pass-123","passwordConfirmation":"secret-pass-123"}'

curl -i -X POST http://localhost:3333/api/v1/posts \
  -H 'Content-Type: application/json' -H 'Accept: application/json' \
  -H 'Authorization: Bearer oat_...' \
  --data '{"title":"First post","body":"Hello"}'
```

なお、Node.js 26で起動すると `module.register()` の非推奨警告（DEP0205）が出ますが、動作には影響しませんでした。

## Lucid ORMの特徴：対応データベースとSQLiteの落とし穴

### Knexベースのクエリビルダーと対応データベース

LucidはKnexの上に作られたActive Record型のORMです。モデルのメソッド（`Post.create`、`findOrFail`、`merge().save()`）でCRUDを書き、複雑な条件は `Post.query()` のクエリビルダーで組み立てます。キットの `config/database.ts` は既定がSQLite（better-sqlite3）で、PostgreSQL（pg）、MySQL（mysql2）、SQL Server（tedious）、libSQL（@libsql/client、Turso向け）の接続例がコメントで用意されています。MariaDBはmysql2クライアントで接続します。ドライバーのパッケージを入れて接続設定を切り替えます。

リレーションは `hasMany`・`belongsTo` などのデコレーターでモデルに宣言し、`preload` で一括読み込みします。同じNode.js向けORMのTypeORMやPrismaとの書き味の違いは、[TypeORMの使い方](/tech/details/7599/)と[TypeORMとPrismaの比較](/tech/details/4331/)が参考になります。

### SQLiteで真偽値が1・0で返る問題とconsumeでの補正

生成された `PostSchema` では `isPublished` の型が `boolean` ですが、SQLiteには真偽値型が無く、読み出した値は数値になります。実際、作成直後のレスポンスは `"isPublished":true` なのに、一覧を取り直すと `"isPublished":1` が返りました。モデル側で列を宣言し直し、`consume` で変換すると一覧でも `false`／`true` が返るようになりました。

```
import { PostSchema } from '#database/schema'
import { column } from '@adonisjs/lucid/orm'

export default class Post extends PostSchema {
  @column({ consume: (value) => Boolean(value) })
  declare isPublished: boolean
}
```

また、`isPublished` を省略して作成したときのレスポンスには `isPublished` 自体が含まれません。データベースの既定値（false）は、保存後にモデルへ読み戻されないためです。作成直後に既定値込みの値を返したい場合は、保存後に `await post.refresh()` を呼びます（追加後のレスポンスに `"isPublished":false` が含まれることを確認）。本番でPostgreSQLを使うなら真偽値の問題は起きませんが、テストだけSQLiteで回す構成では型のずれが出ます。

### シーダーで初期データを投入する手順

`node ace make:seeder Post` で `database/seeders/post_seeder.ts` が作られ、`run()` の中にモデル操作を書いて `node ace db:seed` で投入します。

```
import { BaseSeeder } from '@adonisjs/lucid/seeders'
import Post from '#models/post'

export default class extends BaseSeeder {
  async run() {
    await Post.createMany([
      { title: 'Seeded post 1', body: 'body 1', isPublished: true },
      { title: 'Seeded post 2', body: 'body 2' },
    ])
  }
}
```

## Inertia連携：React・Vueで画面を作る構成

Inertiaはサーバーのルーティングとコントローラーをそのままにしたまま、画面だけをReactやVueのコンポーネントで描く仕組みです。JSON APIを別に設計せず、コントローラーからページ名とpropsを渡します。考え方はLaravelの[Laravel Inertia](/tech/details/17149/)と同じで、コントローラーからページ名とpropsを返す書き方、ページコンポーネントの置き場所の分け方をそのまま移せます。

2026年8月9日公開の @adonisjs/inertia 5.0.0 から、クライアント側はInertia 3（@inertiajs/\* の3系）が必須になりました。npm上の最新は10月22日公開の5.0.5です。reactキットの package.json（2026年11月5日時点の adonisjs/starter-kits の inertia-react）で宣言されている範囲は、@adonisjs/inertia `^5.0.1`、@inertiajs/react `^3.7.1`、react `^19.3.0`、vite `^8.3.0` で、vueキットは @inertiajs/vue3 `^3.7.1`、vue `^3.5.43` です。`config/inertia.ts` にはSSR用の設定と `inertia/ssr.tsx` が用意されていますが、既定値は `ssr: { enabled: false }` です。SSRを有効にすると、初回のHTMLレスポンスにページ本文が描画済みで含まれます。公開ページの初期表示や検索エンジン向けにそれが必要なときに有効化します。

v7のInertia連携では、ルート名とpropsの型がコード生成でフロントへ渡り、型付きの `<Link>`・`<Form>` コンポーネントでURLを組み立てられます。v6のInertia構成からの移行は、アップグレードガイドの「Inertia integration rewrite」でファイル構成と共有データの置き場所の変更が説明されています。

## AdonisJSを選ぶ場面と選ばない場面

向いているのは、少人数でTypeScriptのWebアプリやAPIを一から作り、ORM・認証・バリデーションの選定と配線に時間を使いたくない場合です。Laravelの経験があるチームなら、ルート→コントローラー→モデル→マイグレーションの流れと、Inertiaによる画面構成をほぼそのまま持ち込めます。

次の条件に当てはまる場合は採用しません。

- **Node.js 24へ上げられない実行環境**：v7はNode.js 24未満を切っています。社内の実行基盤やサーバーレスのランタイムが24に対応していなければ、v6に留まるか別のフレームワークを選ぶことになります。
- **ORMにPrismaやDrizzleを使うと決まっている**：Lucidを外すと、スキーマ生成、`unique` 等のDB参照バリデーション、認証のLucid連携（`withAuthFinder` やアクセストークンの保存）を自前で作り直すことになり、その実装と保守の負担が採用の利点を上回ります。
- **既存のNestJS・Expressの資産に一部だけ足したい**：AdonisJSはアプリ全体の構成を前提にするため、既存サーバーへの部分導入には向きません。
- **日本語の情報量を重視する**：国内の解説記事の多くはv6以前のもので、v7の書き方（スキーマクラス、Transformer、バレルファイル）には公式ドキュメントで当たる必要があります。

## AdonisJSに関するよくある質問

### AdonisJSの読み方は？

「アドニスジェイエス」と読み、日本語の記事では「アドニスJS」とも表記されます。ORMのLucidは「ルーシッド」と読みます。表記は公式が「AdonisJS」、パッケージ名が @adonisjs/core です。検索では「adonis js」「adonis.js」のように区切った表記も使われますが、同じフレームワークを指します。Adonisという名前のほかのソフトウェアと区別したいときは「AdonisJS」と続けて書くのが確実です。

### AdonisJSの最新バージョンは？

メジャー版はv7で、v7.0.0は2026年2月25日に公開されました。2026年11月5日時点のnpm上の最新は @adonisjs/core 7.6.0（10月5日公開・codemodsの機能追加）、Lucidは22.4.2、プロジェクト作成用の create-adonisjs は3.4.0です。v7はNode.js 24以上が必須で、v6からは公式アップグレードガイドの手順で移行します。最新の版番号は `npm view @adonisjs/core version` で確認できます。

### AdonisJSはMVCフレームワークですか？

はい。LucidのモデルがModel、Edgeテンプレートまたは Inertia のページがView、app/controllers のクラスがControllerにあたり、ディレクトリ構成もこの分担に沿っています。apiキットのようにViewを持たない構成でも、ルート→コントローラー→モデルの流れは同じです。入力検証はv6から app/validators のValidator（VineJS）に分けて書く形で、v7ではこれにレスポンス整形のTransformerが加わり、出力の責務もコントローラーの外に出ました。

### AdonisJSとNestJSやExpressの違いは？

Expressはルーティングとミドルウェアだけの最小構成で、ORMやバリデーションは自分で選びます。NestJSはDIとモジュール分割の枠組みを提供しますが、ORMは外部から選ぶ前提です。AdonisJSはORM・バリデーション・認証・テストまで公式パッケージで揃える点が違い、選定の手間が少ない代わりに、Lucid以外のORMを使うと利点の多くが消えます。

### AdonisJSのORM（Lucid）でリレーションは使えますか？

使えます。LucidはhasOne・hasMany・belongsTo・manyToMany・hasManyThroughのリレーションを持ち、モデルにデコレーターで宣言して `preload` でまとめて読み込みます。v7ではリレーションもTransformerで整形し、関連データを返すときは関連モデル側のTransformerを呼び出します。Knexベースなので、ORMで書きにくいクエリは `db.rawQuery` で直接SQLを書けます。

## 関連記事

- [Node.jsとは？仕組み・版の選び方・標準機能で動かす手順を実装目線で解説](/tech/details/17433/)
- [Express.jsとは？Node.jsバックエンド入門とExpress 5.3の変更点・4系からの移行](/tech/details/3857/)
- [Laravel Inertiaとは｜APIを作らずSPAを組む仕組みと3系の変更点](/tech/details/17149/)
- [TypeORMとは？1.1系の使い方｜エンティティ・CRUD・リレーション・マイグレーションを実行して解説](/tech/details/7599/)
- [DTOとは？意味・Entityとの違いとNestJSのValidationPipe設定【v12実測】](/tech/details/6208/)

---

出典: [AdonisJSとは？v7のインストールからCRUD API・Inertia連携、脆弱性対応まで実行して解説](<https://www.issoh.co.jp/tech/details/7000/>)（株式会社一創）
