Issue #1 State of JS 2025 Response
State of JavaScript 2025

JavaScript Devs, We Hear You

The same pain points. Year after year. We built AdonisJS to fix them.

We've been there too.

Express is showing its age, but that's the easy part. There are plenty of modern micro-frameworks to pick from. Choosing one gets you maybe 10% of the way there.

The other 90% is everything else. Which libraries do you pair with it? How do you structure your project? What conventions does your team follow? Where do things go when the codebase grows beyond a few files?

Every project. The same ritual. The same frustration.

The State of JS 2025 survey confirmed what we already knew: the backend ecosystem isn't missing tools. It's missing cohesion.

So we asked ourselves: what if the tools were designed to work together from day one?

#2 Pain Point · Static Typing (7%)

TypeScript-first.
Not TypeScript-compatible.

AdonisJS made the shift to TypeScript-first in 2020. Not as a layer on top. As a rewrite with types at the core of every design decision. Every API, every return type, every configuration option is fully typed.

But we didn't stop at the framework. We thought about types at every boundary where things typically break.

Types everywhere it matters.

Environment Variables
Env.get('DATABASE_URL')
// Returns: string
// Typo? Compile error.
    
Request Validation
Env.get('DATABASE_URL')
// Returns: string
// Typo? Compile error.
    
Route URL Builder
Env.get('DATABASE_URL')
// Returns: string
// Typo? Compile error.
    
Database Queries
Env.get('DATABASE_URL')
// Returns: string
// Typo? Compile error.
    
Redirects
Env.get('DATABASE_URL')
// Returns: string
// Typo? Compile error.
    
API Tests
Env.get('DATABASE_URL')
// Returns: string
// Typo? Compile error.
    
#16 Authentication (2%) · #19 Lack of "all-in-one" Framework (2%)

Two complaints. One root cause.

Take something as common as user signup. In most Node.js setups, this is what the process actually looks like:

The Assembly
  1. Pick an auth library.
  2. Read its integration guide for your specific framework.
  3. Configure an adapter for your specific ORM.
  4. Set up a session store compatible with your session middleware.
  5. Map the library's user object to your own model.
  6. Write the glue to make it all hold together.

That's before you've written a single line of product code.

AdonisJS

$ node ace add @adonisjs/auth

It already knows your User model. It already knows your session config. It already works with your middleware.

Write your login route.

And auth is just one feature. Repeat the assembly process for validation, mail, file uploads, background jobs, testing. Each time, a new library, a new integration, a new set of compatibility questions.

This is what happens when auth, ORM, sessions, and middleware are designed as one system.

We applied this thinking to every part of the stack.

All first-party. All integrated.
Auth ORM Validation Mail Sessions File Uploads Background Jobs Testing Env Management CORS & Security
#13 Pain Point · ESM & CJS (3%)

We picked a side.

Half the npm ecosystem is CommonJS. Half is ESM. Mixing them is a special kind of hell. ERR_REQUIRE_ESM at 2am. Mysterious default import issues. Packages that work in development but break in production.

AdonisJS made the hard decision early: we're fully ESM.

The entire framework. The entire official package ecosystem. No dual builds. No compatibility layers. No "just add type: module and pray."

Clean imports. Modern JavaScript.
// No require(). No __dirname hacks. No interop headaches.
import router from '@adonisjs/core/services/router'
import { HttpContext } from '@adonisjs/core/http'
                    
// Just... JavaScript. The way it should be in 2025.
                
#7 Pain Point · Lack of Documentation (4%)

Docs that teach, not just reference.

API references are necessary. But when you're learning a framework, you need guides. Explanations. Context. The "why", not just the "what".

AdonisJS documentation is written for humans trying to build things. Every concept explained. Every feature demonstrated. Every edge case covered.

See for yourself
#5 NestJS (4%) · #6 Excessive Complexity (4%)

Opinionated doesn't mean over-engineered.

Some frameworks mistake complexity for power. Decorators everywhere. Abstract factories. Dependency injection that requires a PhD to debug.

AdonisJS is opinionated. It gives you conventions and structure. But the code you write still looks like... code. You can read a controller and understand what it does. No magic. No ceremony.

Controllers

A resource with auth and validation.

NestJS
@Controller('posts')
    export class PostsController {
        constructor(
            @Inject(PostsService)
            private postsService: PostsService,
        ) {}
                        
        @Get()
        @UseGuards(AuthGuard)
        @UseInterceptors(CacheInterceptor)
        async findAll(): Promise {
            return this.postsService.findAll();
        }
                        
        @Post()
        @UseGuards(AuthGuard)
        @UsePipes(ValidationPipe)
        async create(
            @Body() dto: CreatePostDto
            ): Promise {
            return this.postsService
            .create(dto);
        }
    }
AdonisJS
export default class PostsController {
                            
        async index({ auth }: HttpContext) {
            await auth.authenticate()
            const posts = await Post.all()
            return posts
        }
                            
        async store({ auth, request }: HttpContext) {
            await auth.authenticate()
            const data = await request
            .validateUsing(createPostValidator)
            return await Post.create(data)
        }
    }
                            
    // No decorators. No injected services.
    // Just functions that do things.
                        

Validation

Validating a create post request.

NestJS — create-post.dto.ts
// npm install class-validator
// npm install class-transformer

export class CreatePostDto {
    @IsString()
    @IsNotEmpty()
    @MinLength(3)
    title: string;

    @IsString()
    @IsOptional()
    @MaxLength(5000)
    body?: string;

    @IsArray()
    @IsString({ each: true })
    tags: string[];
}
AdonisJS — post_validator.ts
import vine from '@vinejs/vine'
                
export const createPostValidator = vine
    .compile(
        vine.object({
            title: vine.string()
                .minLength(3),
            body: vine.string()
                .maxLength(5000)
                .optional(),
            tags: vine.array(
                vine.string()
        ),
    })
)

// No decorators. No classes.
// Schema in, typed data out.

Module Registration

The hidden tax. Every feature needs one.

NestJS — posts.module.ts + app.module.ts
// posts.module.ts
@Module({
    imports: [
        TypeOrmModule.forFeature([Post]),
        AuthModule,
    ],
    controllers: [PostsController],
    providers: [
        PostsService,
        PostsRepository,
    ],
    exports: [PostsService],
})

export class PostsModule {}
                
// app.module.ts
@Module({
    imports: [
        PostsModule,
        UsersModule,
        AuthModule,
        MailModule,
        // ...every feature gets one
    ],
})
export class AppModule {}
AdonisJS — start/routes.ts
import router from '@adonisjs/core/services/router'
                
router
    .resource('posts', '#controllers/posts_controller')
    .middleware('auth')




// No module file.
// No provider registration.
// No exports array.
//
// Create the controller.
// Reference it in routes.
// Done.

Both frameworks are opinionated. Both are typed. Both have structure. The difference is in how much framework you have to write before you write your application.

Let's do something different today.

You've assembled the stack before. You've read the integration guides, wired the adapters, mapped the types. You know how that story ends.

Terminal
$ npm create adonisjs@latest my-app
Select a starter kit
Hypermedia Server-rendered with Edge templates
React Single-page app with Inertia
Vue Single-page app with Inertia
API JSON API with token auth

Pick your frontend. Everything else is included:

  • Router & Controllers
  • ORM & Migrations
  • Validation
  • Authentication
  • Sessions
  • Env Management
  • Mail
  • File Uploads
  • Background Jobs
  • Testing Utilities
  • CORS & Security
  • Edge Templating