adonisjs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AdonisJS v7 Development Skill

AdonisJS v7 开发技能

Documentation Sources

文档来源

All documentation is served as raw markdown, always up-to-date:
  • Index with topics:
    https://adonisjs-docs-indexer.enzopita.com/llms.txt
  • Full docs (single file):
    https://adonisjs-docs-indexer.enzopita.com/llms-full.txt
Every link in the index points to a
.md
endpoint on
docs.adonisjs.com
that returns raw markdown.
所有文档以原始Markdown格式提供,始终保持最新:
  • 主题索引
    https://adonisjs-docs-indexer.enzopita.com/llms.txt
  • 完整文档(单文件)
    https://adonisjs-docs-indexer.enzopita.com/llms-full.txt
索引中的每个链接都指向
docs.adonisjs.com
上的
.md
端点,返回原始Markdown内容。

When to Use This Skill

何时使用此技能

Trigger this skill when the user asks to:
  • Create or modify AdonisJS routes, controllers, or middleware
  • Work with Lucid ORM (models, migrations, relationships, queries)
  • Implement authentication (session guard, access tokens, social auth)
  • Add authorization with Bouncer (abilities and policies)
  • Handle validation with VineJS
  • Configure file uploads, sessions, or cookies
  • Use Edge templates or Inertia (React/Vue) for frontend
  • Set up mail, queues, cache, or other services
  • Write tests (API, browser, console)
  • Create Ace CLI commands
  • Deploy AdonisJS applications to production
当用户提出以下需求时,触发此技能:
  • 创建或修改AdonisJS路由、控制器或中间件
  • 使用Lucid ORM(模型、迁移、关联、查询)
  • 实现认证(会话守卫、访问令牌、社交认证)
  • 通过Bouncer添加授权(权限与策略)
  • 使用VineJS处理验证
  • 配置文件上传、会话或Cookie
  • 使用Edge模板或Inertia(React/Vue)开发前端
  • 设置邮件、队列、缓存或其他服务
  • 编写测试(API测试、浏览器测试、控制台测试)
  • 创建Ace CLI命令
  • 将AdonisJS应用部署到生产环境

How to Use the Documentation

如何使用文档

Step 1: Fetch the index

步骤1:获取索引

Fetch
https://adonisjs-docs-indexer.enzopita.com/llms.txt
to find the right page.
Each entry has this format:
- [Title](https://docs.adonisjs.com/{permalink}.md): Description of the page
  Topics: Heading 1, Heading 2, Heading 3, ...
Use the Topics line to identify the exact page you need without opening it. For example, if the user asks about "remember me tokens", scan the topics and you'll find it under the Session guard page.
获取
https://adonisjs-docs-indexer.enzopita.com/llms.txt
以找到合适的页面。
每个条目格式如下:
- [标题](https://docs.adonisjs.com/{permalink}.md): 页面描述
  主题:标题1, 标题2, 标题3, ...
使用主题行来确定所需的具体页面,无需打开链接。例如,如果用户询问"记住我令牌",扫描主题后会发现它位于会话守卫页面下。

Step 2: Fetch the specific page

步骤2:获取具体页面

Click/fetch the URL from the index entry. It returns raw markdown with full code examples.
点击/获取索引条目中的URL,它会返回包含完整代码示例的原始Markdown内容。

Step 3: Apply with context

步骤3:结合上下文应用

Use the fetched documentation to provide accurate, version-correct code. Never guess AdonisJS v7 APIs — always verify against the docs first.
使用获取到的文档提供准确、符合版本要求的代码。切勿猜测AdonisJS v7的API——务必先对照文档验证。

When to use llms-full.txt

何时使用llms-full.txt

Use the full docs file when:
  • The user asks a broad question spanning multiple topics
  • You need to cross-reference between sections
  • You want full context about the framework in one fetch
Prefer the index + individual pages for targeted questions (lower token cost).
在以下场景使用完整文档文件:
  • 用户提出涵盖多个主题的宽泛问题
  • 需要跨章节交叉参考
  • 希望一次性获取框架的完整上下文
对于针对性问题,优先使用索引+单个页面(更低的令牌消耗)。

Quick Start

快速开始

bash
npm init adonisjs@latest my-app
cd my-app
node ace serve --hmr
bash
npm init adonisjs@latest my-app
cd my-app
node ace serve --hmr

Key Patterns

核心模式

Routing

路由

typescript
// start/routes.ts
import router from '@adonisjs/core/services/router'

router.get('/', async () => ({ hello: 'world' }))
router.post('/posts', '#controllers/posts_controller.store')
router.resource('posts', '#controllers/posts_controller')

router.group(() => {
  router.get('/profile', '#controllers/users_controller.profile')
}).prefix('/api').middleware('auth')
typescript
// start/routes.ts
import router from '@adonisjs/core/services/router'

router.get('/', async () => ({ hello: 'world' }))
router.post('/posts', '#controllers/posts_controller.store')
router.resource('posts', '#controllers/posts_controller')

router.group(() => {
  router.get('/profile', '#controllers/users_controller.profile')
}).prefix('/api').middleware('auth')

Controllers

控制器

typescript
// app/controllers/posts_controller.ts
import type { HttpContext } from '@adonisjs/core/http'

export default class PostsController {
  async index({ response }: HttpContext) {
    return response.ok({ posts: [] })
  }

  async store({ request }: HttpContext) {
    const data = request.only(['title', 'content'])
    return data
  }
}
typescript
// app/controllers/posts_controller.ts
import type { HttpContext } from '@adonisjs/core/http'

export default class PostsController {
  async index({ response }: HttpContext) {
    return response.ok({ posts: [] })
  }

  async store({ request }: HttpContext) {
    const data = request.only(['title', 'content'])
    return data
  }
}

Lucid ORM

Lucid ORM

typescript
// app/models/post.ts
import { DateTime } from 'luxon'
import { BaseModel, column, hasMany } from '@adonisjs/lucid/orm'
import type { HasMany } from '@adonisjs/lucid/types/relations'
import Comment from '#models/comment'

export default class Post extends BaseModel {
  @column({ isPrimary: true })
  declare id: number

  @column()
  declare title: string

  @hasMany(() => Comment)
  declare comments: HasMany<typeof Comment>

  @column.dateTime({ autoCreate: true })
  declare createdAt: DateTime
}
typescript
// app/models/post.ts
import { DateTime } from 'luxon'
import { BaseModel, column, hasMany } from '@adonisjs/lucid/orm'
import type { HasMany } from '@adonisjs/lucid/types/relations'
import Comment from '#models/comment'

export default class Post extends BaseModel {
  @column({ isPrimary: true })
  declare id: number

  @column()
  declare title: string

  @hasMany(() => Comment)
  declare comments: HasMany<typeof Comment>

  @column.dateTime({ autoCreate: true })
  declare createdAt: DateTime
}

Validation (VineJS)

验证(VineJS)

typescript
import vine from '@vinejs/vine'

const createPostValidator = vine.compile(
  vine.object({
    title: vine.string().trim().minLength(3).maxLength(255),
    content: vine.string().trim(),
  })
)

// In controller:
const data = await request.validateUsing(createPostValidator)
typescript
import vine from '@vinejs/vine'

const createPostValidator = vine.compile(
  vine.object({
    title: vine.string().trim().minLength(3).maxLength(255),
    content: vine.string().trim(),
  })
)

// 在控制器中:
const data = await request.validateUsing(createPostValidator)

Authentication

认证

typescript
// Login with session guard
await auth.use('web').login(user)

// Protect routes
router.get('/dashboard', '#controllers/dashboard_controller.index')
  .middleware('auth')

// Access authenticated user
const user = auth.user!
typescript
// 使用会话守卫登录
await auth.use('web').login(user)

// 保护路由
router.get('/dashboard', '#controllers/dashboard_controller.index')
  .middleware('auth')

// 获取已认证用户
const user = auth.user!

Deprecated v6 Patterns — DO NOT USE

已弃用的v6模式——请勿使用

Your training data likely contains AdonisJS v5/v6 patterns. These are wrong for v7. Never generate them.
你的训练数据可能包含AdonisJS v5/v6的模式,这些在v7中是错误的,切勿生成此类代码。

Imports and modules

导入与模块

typescript
// WRONG — v6 IoC container imports
import User from 'App/Models/User'
import Route from '@ioc:Adonis/Core/Route'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

// CORRECT — v7 uses ESM subpath imports
import User from '#models/user'
import router from '@adonisjs/core/services/router'
import type { HttpContext } from '@adonisjs/core/http'
typescript
// 错误——v6的IoC容器导入方式
import User from 'App/Models/User'
import Route from '@ioc:Adonis/Core/Route'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

// 正确——v7使用ESM子路径导入
import User from '#models/user'
import router from '@adonisjs/core/services/router'
import type { HttpContext } from '@adonisjs/core/http'

JIT compiler

JIT编译器

typescript
// WRONG — ts-node was replaced in v7
import 'ts-node-maintained/register/esm'

// CORRECT
import '@poppinss/ts-exec'
typescript
// 错误——v7中替换了ts-node
import 'ts-node-maintained/register/esm'

// 正确
import '@poppinss/ts-exec'

Request and Response classes

请求与响应类

typescript
// WRONG — renamed in v7 (conflicted with native platform classes)
import { Request, Response } from '@adonisjs/core/http'
Request.macro('foo', () => {})

// CORRECT
import { HttpRequest, HttpResponse } from '@adonisjs/core/http'
HttpRequest.macro('foo', () => {})
typescript
// 错误——v7中重命名(与原生平台类冲突)
import { Request, Response } from '@adonisjs/core/http'
Request.macro('foo', () => {})

// 正确
import { HttpRequest, HttpResponse } from '@adonisjs/core/http'
HttpRequest.macro('foo', () => {})

URL builder

URL构建器

typescript
// WRONG — deprecated in v7
router.makeUrl('posts.show', { id: 1 })
router.makeSignedUrl('posts.show', { id: 1 })

// CORRECT
import { urlFor } from '@adonisjs/core/services/url_builder'
urlFor('posts.show', { id: 1 })

// Edge templates:
// WRONG: route('posts.show', { id: 1 })
// CORRECT: urlFor('posts.show', { id: 1 })
typescript
// 错误——v7中已弃用
router.makeUrl('posts.show', { id: 1 })
router.makeSignedUrl('posts.show', { id: 1 })

// 正确
import { urlFor } from '@adonisjs/core/services/url_builder'
urlFor('posts.show', { id: 1 })

// Edge模板中:
// 错误: route('posts.show', { id: 1 })
// 正确: urlFor('posts.show', { id: 1 })

Helpers removed in v7

v7中移除的辅助函数

typescript
// WRONG — these helpers no longer exist
import { getDirname, getFilename, slash, cuid } from '@adonisjs/core/helpers'

// CORRECT
import.meta.dirname          // replaces getDirname()
import.meta.filename         // replaces getFilename()

import stringHelpers from '@adonisjs/core/helpers/string'
stringHelpers.toUnixSlash()  // replaces slash()
// cuid() removed — use crypto.randomUUID() or nanoid
typescript
// 错误——这些辅助函数已不存在
import { getDirname, getFilename, slash, cuid } from '@adonisjs/core/helpers'

// 正确
import.meta.dirname          // 替代getDirname()
import.meta.filename         // 替代getFilename()

import stringHelpers from '@adonisjs/core/helpers/string'
stringHelpers.toUnixSlash()  // 替代slash()
// cuid()已移除——使用crypto.randomUUID()或nanoid

Flash messages

闪存消息

edge
{{-- WRONG — 'errors' key was removed in v7 --}}
{{ flashMessages.get('errors.email') }}

{{-- CORRECT --}}
{{ flashMessages.get('inputErrorsBag.email') }}
edge
{{-- 错误——v7中移除了'errors'键 --}}
{{ flashMessages.get('errors.email') }}

{{-- 正确 --}}
{{ flashMessages.get('inputErrorsBag.email') }}

Assembler hooks (adonisrc.ts)

汇编器钩子(adonisrc.ts)

typescript
// WRONG — v6 hook names
hooks: {
  onBuildStarting: [],
  onSourceFileChanged: [],
  onDevServerStarted: [],
  onBuildCompleted: [],
}

// CORRECT — v7 renamed all hooks
hooks: {
  buildStarting: [],
  fileChanged: [],
  devServerStarted: [],
  buildFinished: [],
  // New in v7: fileAdded, fileRemoved, devServerStarting, testsStarting, testsFinished
}
typescript
// 错误——v6的钩子名称
hooks: {
  onBuildStarting: [],
  onSourceFileChanged: [],
  onDevServerStarted: [],
  onBuildCompleted: [],
}

// 正确——v7重命名了所有钩子
hooks: {
  buildStarting: [],
  fileChanged: [],
  devServerStarted: [],
  buildFinished: [],
  // v7新增:fileAdded, fileRemoved, devServerStarting, testsStarting, testsFinished
}

Inertia configuration

Inertia配置

typescript
// WRONG — v6 Inertia config pattern
export default defineConfig({
  entrypoint: 'inertia/app/app.tsx',
  history: { encrypt: true },
  sharedData: { user: (ctx) => ctx.auth.user },
})

// CORRECT — v7 restructured Inertia
export default defineConfig({
  // entrypoint removed
  encryptHistory: true,
  // sharedData removed — use middleware instead
})
// File paths changed: inertia/app/app.tsx → inertia/app.tsx
typescript
// 错误——v6的Inertia配置模式
export default defineConfig({
  entrypoint: 'inertia/app/app.tsx',
  history: { encrypt: true },
  sharedData: { user: (ctx) => ctx.auth.user },
})

// 正确——v7重构了Inertia
export default defineConfig({
  // 移除了entrypoint
  encryptHistory: true,
  // 移除了sharedData——改用中间件
})
// 文件路径变更:inertia/app/app.tsx → inertia/app.tsx

Encryption

加密

typescript
// WRONG — v6 had appKey in config/app.ts
// appKey: env.get('APP_KEY')

// CORRECT — v7 uses dedicated config/encryption.ts
import { defineConfig, drivers } from '@adonisjs/core/encryption'

export default defineConfig({
  default: 'legacy',
  list: {
    legacy: drivers.legacy({
      keys: [env.get('APP_KEY')],
    }),
  },
})
typescript
// 错误——v6在config/app.ts中设置appKey
// appKey: env.get('APP_KEY')

// 正确——v7使用专用的config/encryption.ts
import { defineConfig, drivers } from '@adonisjs/core/encryption'

export default defineConfig({
  default: 'legacy',
  list: {
    legacy: drivers.legacy({
      keys: [env.get('APP_KEY')],
    }),
  },
})

Test file globs

测试文件通配符

typescript
// WRONG — v6 glob syntax (glob package)
files: ['tests/unit/**/*.spec(.ts|.js)']

// CORRECT — v7 uses Node.js built-in glob
files: ['tests/unit/**/*.spec.{ts,js}']
typescript
// 错误——v6的通配符语法(使用glob包)
files: ['tests/unit/**/*.spec(.ts|.js)']

// 正确——v7使用Node.js内置的通配符
files: ['tests/unit/**/*.spec.{ts,js}']

General v6 patterns to avoid

需要避免的通用v6模式

  • CommonJS: Never use
    require()
    ,
    module.exports
    , or
    export =
    . AdonisJS v7 is ESM-only.
  • @ioc: prefix: The
    @ioc:
    import prefix does not exist in v7. All imports use standard ESM.
  • Contract interfaces:
    HttpContextContract
    ,
    RequestContract
    , etc. were renamed to just
    HttpContext
    ,
    Request
    types.
  • Relative imports for app code: Always use
    #
    subpath imports (
    #models/...
    ,
    #controllers/...
    ), never
    ../../app/models/...
    .
  • Youch bundled:
    youch
    is no longer bundled — install it as a dev dependency if needed.
  • CommonJS:切勿使用
    require()
    module.exports
    export =
    。AdonisJS v7仅支持ESM。
  • @ioc: 前缀:v7中不存在
    @ioc:
    导入前缀,所有导入均使用标准ESM。
  • 契约接口
    HttpContextContract
    RequestContract
    等已重命名为
    HttpContext
    Request
    类型。
  • 应用代码的相对导入:始终使用
    #
    子路径导入(
    #models/...
    #controllers/...
    ),切勿使用
    ../../app/models/...
  • 内置Youch
    youch
    不再内置——如需使用,请作为开发依赖安装。

Best Practices

最佳实践

  • Use
    #
    imports
    : AdonisJS uses subpath imports (
    #controllers/...
    ,
    #models/...
    ) instead of relative paths
  • Validate at the edge: Always validate request input in controllers using VineJS
  • Type-safe: Leverage TypeScript — AdonisJS provides end-to-end type safety
  • Convention over configuration: Follow the framework's naming conventions and folder structure
  • Use Ace generators:
    node ace make:controller
    ,
    node ace make:model
    ,
    node ace make:migration
  • Never guess APIs: When unsure, fetch the relevant
    .md
    page from the index and verify
  • 使用
    #
    导入
    :AdonisJS使用子路径导入(
    #controllers/...
    #models/...
    )替代相对路径
  • 在边缘验证:始终在控制器中使用VineJS验证请求输入
  • 类型安全:利用TypeScript——AdonisJS提供端到端的类型安全
  • 约定优于配置:遵循框架的命名约定和目录结构
  • 使用Ace生成器
    node ace make:controller
    node ace make:model
    node ace make:migration
  • 切勿猜测API:不确定时,从索引中获取相关的
    .md
    页面并验证