Introducing AdonisJS - Your Gateway to Full-stack TypeScript Applications

This ad is not shown to multipass and full ticket holders
React Summit US
React Summit US 2025
November 18 - 21, 2025
New York, US & Online
The biggest React conference in the US
Learn More
In partnership with Focus Reactive
Upcoming event
React Summit US 2025
React Summit US 2025
November 18 - 21, 2025. New York, US & Online
Learn more
Bookmark
Rate this content

Most JavaScript frameworks are born out of the frontend ecosystem and slowly move toward the backend as meta frameworks. AdonisJS takes the opposite approach, emphasizing solving backend problems and staying agnostic about the frontend stack.

In this talk, we will provide an overview of AdonisJS and how it could be your gateway to building full-stack monolithic applications using TypeScript.

This talk has been presented at Node Congress 2025, check out the latest edition of this JavaScript Conference.

FAQ

Adonis.js is a full-stack MVC framework for creating web applications or JSON APIs using TypeScript and Node.js. It is back-end first and allows you to choose any front-end stack.

Adonis.js was created by Harmendar Virk.

Adonis.js is a TypeScript first framework with a focus on type safety. It uses Node.js features like subpart imports and async local storage, and is designed for teams and individuals who prefer opinionated, batteries-included frameworks.

Adonis.js handles CRUD operations using routing, controllers, models, and views. It uses SQL ORM, supports authentication, file uploads, and password hashing to facilitate development.

You can start a new Adonis.js project by running the command: npm init adonis <project-name>.

Models in Adonis.js are used to interact with the database, while migrations are used to create and alter database tables.

Adonis.js includes a pre-configured package for user authentication, supporting sessions, API tokens, and basic HTTP auth.

The Edge template engine is used to render HTML pages in Adonis.js, but it can be replaced with any other template engine or front-end framework.

Adonis.js uses Wine.js, an in-house validation library that is type-safe and integrates well with the framework.

You can learn more about Adonis.js by visiting the official website at AdonisJS.com, following updates on Twitter, or joining the community on Discord.

Harminder Virk
Harminder Virk
23 min
17 Apr, 2025

Comments

Sign in or register to post your comment.
Video Summary and Transcription
Today we are going to talk about Adonis.js, a full-stack framework for creating web applications or JSON APIs in TypeScript and Node.js. Adonis.js is TypeScript first, embraces Node.js, and is designed for teams and individuals who prefer opinionated frameworks. We are going to build a simplistic version of Product Hunt called OS Hunt in Adonis.js. We will define routes, create a controller, and interact with the database. Adonis.js provides pre-configured tools for handling form submissions and validating user input. User authentication and registration can be implemented without third-party packages. Adonis.js integrates tightly with the Wine validation library and has support for email verification.

1. Introduction to Adonis.js

Short description:

Today we are going to talk about Adonis.js, a full-stack framework for creating web applications or JSON APIs in TypeScript and Node.js. Adonis.js is an MVC framework that allows you to work with models, controllers, and views. It is a back-end first framework and can be used with any front-end stack. Adonis.js is TypeScript first, embraces Node.js, and is designed for teams and individuals who prefer opinionated frameworks.

All right, so today we are going to talk about Adonis.js, which is a full-stack framework you can use to create web applications or JSON APIs written in TypeScript and Node.js. First, let me start by introducing myself. My name is Harmendar Virk. I am the creator of Adonis.js, and currently I'm working with Medusa, which is an e-commerce platform slash framework for developers. I'm from India and I'm a dad to a four-year-old daughter, and you can find me on Twitter with this handle, at the rate Amanvirk1.

Now, this talk is going to be very code intensive, where I will be sharing a lot of code snippets with you. But before we do that, let's take a moment and talk about Adonis.js from a more fundamental and philosophical point of view. So, Adonis.js is an MVC framework, which means when you are writing your applications, you will be dealing with the classic MVC flow, where you will be using models to interact with the database, you will be writing controllers to handle the HTTP request, and then using views to basically display HTML to the users.

Adonis.js is not a meta framework, so a lot of popular frameworks in the JavaScript ecosystem are born out of the front-end ecosystem, where they are usually tied to a front-end library, like Vue or React, and then they go towards back-end, trying to solve some of the problems in the back-end space. Whereas Adonis.js is completely opposite. We are a back-end first framework, and you have the freedom to choose any front-end stack you want. So, you can use it with Vue, React, or like a classic template engine, as I will show you in this talk. We are a TypeScript first framework, which basically means type safety plays a major role when we are designing the framework APIs and features. So, anytime we are working on any new API, we want to make sure that it's completely type-safe and don't go with the choices, which basically breaks that type safety. We also embrace the platform, which is Node.js in our case, to its fullest, which means anytime Node.js releases anything, we try to use it instead of other npm libraries or having our own solutions for it. For example, in order to implement the import aliases, we use subpart imports, which is supported by Node. We use async local storage or async context during the HTTP request, so that anywhere in your application you can pull in the request-related information. And very recently, we started integrating all the framework tracing with the diagnostic channels, which is, again, like a first-class API from Node. And finally, Adonis.js is a framework, which is for teams and individuals who appreciate opinionated frameworks or like batteries-included frameworks.

2. Building OS Hunt in Adonis.js

Short description:

We are going to build a simplistic version of Product Hunt called OS Hunt in Adonis.js. After creating a new project, we will define routes for managing projects, create a controller for handling different HTTP requests, and interact with the database using models and migrations.

All right, so that was like all about Adonis.js. Now we can start diving into some code. So we are going to play a scenario here in which we are trying to build a simplistic version of Product Hunt to showcase all the amazing open-source projects on the internet, and we are going to call it OS Hunt. Now, of course, we are not going to build the entire application, but we will cover all the touch points to see what it takes to build an app like this in Adonis.js.

So first things first, we have to create a new project, and we can do that by running this command, npm init adonis and the name of the project. And after running this command, we will get a new Adonis.js application, which comes with a SQL ORM, support for authentication, file uploads, password hashing, basically all the things we need to kickstart our development. Also, this is how the folder structure of a brand-new Adonis.js application looks like, where everything has its own place where it lives, and you don't have to figure it out by your own.

Okay, so the very first thing we want to do right after creating our application is to see how quickly we can knock out the CRUD operations of our application. And in our case, it's going to be basically creating, reading, updating, and deleting projects. All right, so everything starts with routing, where routes are essentially the HTTP entry points of your application. And this is how you can define them. So in our case, we roughly need these seven endpoints to manage our projects. Very first, we will have an endpoint to list all the projects. And then we got our two endpoints to display the form to create a new project and then handle the submission to basically save that project in the database. And then we want to show a project by its slug, then another couple of endpoints to manage updating a project, and finally an endpoint to delete the project. Once we have defined our routes, we can create a controller for it so that we don't have to write all the logic in this one massive routes file.

And we can create a controller by using this command called node ace make controller, and then the name of the controller we want to create. And once we have created our controller, we can go back to our routes file and we can replace all these inline callbacks with the controller references. So here we are saying, we want to use the project's controller for all these endpoints, but we want to use different methods to handle different routes. And this is how essentially a controller looks like where it's a vanilla JavaScript class with all the methods we want to create to handle different HTTP requests. Now, before we start putting any logic inside our controllers, we need a way to interact with our database so that we can fetch projects from there and we can also save our projects inside the database. And this is where we will move to our next layer of MVC called models.

So models are basically a way for you to interact with the database and migrations is a way to create and alter database tables or like create indexes and drop indexes and all that stuff. So you can create a new model along with a migration using this command, which is node ace make model, the name of the model and dash M flag to basically say you also want a migration along with the model. Once you have the migration file, you can essentially write the instructions you want to create a new table. In our case, we need a table with a primary key. That's the ID, the name of the project, its unique slug, description of the project and the URL that someone can click and go to the project website. And this is how a model looks like, where we will be like using the migration to just create the table. But in our application to interact with that table, we will be using a model and the models are represented as JavaScript classes again.

3. Working with Views and Form Submissions

Short description:

Now let's move forward and see how we can handle form submissions and validate the user input. Every Adonis JS application comes with a pre-configured body parser and Wine.js for validation. We will create a validator with a schema for our form and update the controller's store method to validate the user input. Finally, we give the validated payload to our project model and create a new entry inside the database.

All right, now that we have our database table and we have a model, we can move to the final part of our MVC layer, which is the views. In this example, I will use an in-house template engine called Edge to render HTML pages. But you can very easily replace the view layer with any other template engine or even a front-end framework like Vue or React.

In order to use our views, we will have to move back to our controller, which is completely empty right now apart from these methods, and we can start putting some code inside it. So out here we are saying we will import our project model and then we will create a new query and paginate the results. And once we have all those projects, we will call vue.render, give it the path of the template and pass the projects by reference so that we can access these projects inside our template and we can render them.

Now, let's move forward and see how we can handle form submissions and validate the user input. Every Adonis JS application comes with a pre-configured body parser, which is capable of parsing JSON payloads, multipart bodies, which contain file uploads, and also URL encoded forms. In order to validate the user input, we will be using Wine.js, an in-house validation library that is type safe, super fast, and integrates tightly with the rest of the framework. We will create a new validator by running the command 'make validator' and then the name of the validator we want to create. Within that file, we will define our schema, which is essentially a list of properties we want to accept in our form and validate. Once we have defined our validation schema, we can update the implementation of the store method in our controller to validate the user input using this validation schema. Finally, we give the validated payload to our project model and create a new entry inside the database.

4. Handling Form Submissions and Validation

Short description:

Now let's move forward and see how we can handle form submissions and validate the user input. Every Adonis JS application comes with a pre-configured body parser and Wine.js for validation. We will create a validator with a schema for our form and update the controller's store method to validate the user input. Finally, we give the validated payload to our project model and create a new entry inside the database.

And finally, we are able to render an HTML template by fetching data from the database. So now let's move forward and see how we can handle form submissions and validate the user input.

Now, every Adonis JS application comes with a pre-configured body parser, which is capable of parsing JSON payloads, multipart bodies, essentially, which contain file uploads and also URL encoded forms. And in order to validate the user input, we will be using Wine.js, which is, again, an in-house validation library. It's type safe. It's super fast. And it integrates very tightly with the rest of the framework. And I'll show you how.

So what we are going to do is we are going to create a new validator by running this command, make validator, and then the name of the validator we want to create. Within that file, we will define our schema. It's essentially a list of properties we want to accept in our form, and we want to validate it. Once we have defined our validation schema, we can again go back to our controller and write the logic to validate the user input using this validation schema. So we will update the implementation of the store method. We will pull in the request and the response from our HTTP context. And out here, we will say that we want to validate the request body using this create project validator. And once the validation is done, we will get back a payload object, and it's essentially type safe, so you can see all the properties in there and what their types are. Finally, we give this payload to our project model, and we create a new entry inside the database. And finally, we redirect the user back to the project slash products slot page so that they can view an individual project.

So this is how essentially CRUD works inside an Adonis JS application. You start by defining routes. Then you define a controller. Within the controller, you write all the logic to handle the request. You can use models and validators to essentially validate the user input versus data in the database and fetch data from the database. I won't implement all the remaining methods because they are, like, essentially the same. You have to use the model and fetch or persist necessary information inside the database. But we will move forward, and we will see how we can do things beyond the basics, essentially things like implementing authentication, sending emails to newly registered users, and maybe writing a couple of tests for this application. So let's start with auth. Adonis JS comes with a first-party pre-configured package to authenticate your users. And you can use different authentication cards to perform the authentication. You can use sessions.

5. User Authentication and Registration

Short description:

You can use API tokens or basic HTTP auth for authentication. Implementing auth in Adonis JS is simple and does not require third-party packages. User registration and email sending can be handled using a first-party package with support for various mailing services. Validation of user input is essential when creating new users, and Adonis JS integrates tightly with the Wine validation library to ensure data integrity.

You can use API tokens. Or you can even use, like, basic HTTP auth. So in order to implement auth, again, we are going to define two routes. We will create a new controller. And within our controller, we will write the logic to perform the authentication. So once again, we will use our request object to fetch the email and the password from the request body. We will give this email password to the user model, which already exists when you create a new Adonis JS app. And we will call this method called verify credentials. Once the credentials have been verified, we will get back a user object. And then we can use this auth object, which exists within this HTTP context, to log in the user. And once the user is logged in, we can redirect them back to the project's endpoint so that they can view all the projects.

Okay, so that's how simple authentication looks like in Adonis JS. You don't have to pull in any third-party packages or do anything special. Everything is baked in. Now let's see how we can handle the user registration and how we can send email every time a user registers. One more time, we are going to use a first-party package for that. And it has support for sending emails using SMTP, Mailgun, Amazon SES, SparkPost, Resend, and many more mailing services. So one more time, we go back to our routes file. We define the endpoints for user registration. We create a new controller. And within that controller, we will write the logic to create a new user. So we use our request object. We pull the user full name, email, password, give that payload to our model, and create a new user. Once that's done, we will again use our auth object, and we will log in the user and redirect them to the project's page. But if you go back, you will notice out here when we are reading the user input, we are not validating it, which is ideally not a good decision, at least like when we are creating new users, we should always validate the data before we write it to the database. So that's why we are going to create another validator, and here we will define the schema. So we say we need the full name, we need email, and we need the password. And out here, if you notice, we have a rule called unique, and we are telling this unique rule that we want to make sure that this email is unique inside the user's table, and we should search for the email column. And this is where you can see how tightly the validation library, which is wine, integrates with the rest of the framework. You don't have to like do a first pass of validations and then like write a query yourself to check if the email is unique or not.

6. User Validation and Email Verification

Short description:

You can use the validator to check values inside the database and ensure password confirmation. Additionally, you can send email verification using the mail service from the AdonisJS mail package.

You can just use the validator and rely on these database-specific rules to check for the values inside the database. And then we also have a confirmed rule, which essentially means that the user will have to type the password twice so that they are confirming their password when they are submitting the form. And then we can go back to our controller, and we can replace our request.only method with request.validateUsing to validate the user input and then persist the user in the database.

All right, but what about sending an email? We have created a new user. We have logged them in, we have redirected them, but we haven't sent any email for them to verify their email address. Well, we can do that quite easily by pulling in the mail service from the AdonisJS slash mail package. And out here we can say mail.sendLater, and then we can compose our message that we want to send. And this mail.sendLater method will essentially queue the email inside an in-memory queue, but you can also replace this in-memory queue with a more persistent queue like BulMQ or Amazon SQS. You can do that quite easily.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React's Most Useful Types
React Day Berlin 2023React Day Berlin 2023
21 min
React's Most Useful Types
Top Content
Watch video: React's Most Useful Types
Today's Talk focuses on React's best types and JSX. It covers the types of JSX and React components, including React.fc and React.reactnode. The discussion also explores JSX intrinsic elements and react.component props, highlighting their differences and use cases. The Talk concludes with insights on using React.componentType and passing components, as well as utilizing the react.element ref type for external libraries like React-Select.
Full Stack Components
Remix Conf Europe 2022Remix Conf Europe 2022
37 min
Full Stack Components
Top Content
RemixConf EU discussed full stack components and their benefits, such as marrying the backend and UI in the same file. The talk demonstrated the implementation of a combo box with search functionality using Remix and the Downshift library. It also highlighted the ease of creating resource routes in Remix and the importance of code organization and maintainability in full stack components. The speaker expressed gratitude towards the audience and discussed the future of Remix, including its acquisition by Shopify and the potential for collaboration with Hydrogen.
TypeScript and React: Secrets of a Happy Marriage
React Advanced 2022React Advanced 2022
21 min
TypeScript and React: Secrets of a Happy Marriage
Top Content
React and TypeScript have a strong relationship, with TypeScript offering benefits like better type checking and contract enforcement. Failing early and failing hard is important in software development to catch errors and debug effectively. TypeScript provides early detection of errors and ensures data accuracy in components and hooks. It offers superior type safety but can become complex as the codebase grows. Using union types in props can resolve errors and address dependencies. Dynamic communication and type contracts can be achieved through generics. Understanding React's built-in types and hooks like useState and useRef is crucial for leveraging their functionality.
RedwoodJS: The Full-Stack React App Framework of Your Dreams
React Summit Remote Edition 2021React Summit Remote Edition 2021
43 min
RedwoodJS: The Full-Stack React App Framework of Your Dreams
Top Content
Redwood JS is a full stack React app framework that simplifies development and testing. It uses a directory structure to organize code and provides easy data fetching with cells. Redwood eliminates boilerplate and integrates Jest and Storybook. It supports pre-rendering and provides solutions for authentication and deployment. Redwood is a cross-client framework that allows for building web and mobile applications without duplicating work.
Making Magic: Building a TypeScript-First Framework
TypeScript Congress 2023TypeScript Congress 2023
31 min
Making Magic: Building a TypeScript-First Framework
Top Content
Daniel Rowe discusses building a TypeScript-first framework at TypeScript Congress and shares his involvement in various projects. Nuxt is a progressive framework built on Vue.js, aiming to reduce friction and distraction for developers. It leverages TypeScript for inference and aims to be the source of truth for projects. Nuxt provides type safety and extensibility through integration with TypeScript. Migrating to TypeScript offers long-term maintenance benefits and can uncover hidden bugs. Nuxt focuses on improving existing tools and finds inspiration in frameworks like TRPC.
Stop Writing Your Routes
Vue.js London 2023Vue.js London 2023
30 min
Stop Writing Your Routes
Top Content
Designing APIs is a challenge, and it's important to consider the language used and different versions of the API. API ergonomics focus on ease of use and trade-offs. Routing is a misunderstood aspect of API design, and file-based routing can simplify it. Unplugging View Router provides typed routes and eliminates the need to pass routes when creating the router. Data loading and handling can be improved with data loaders and predictable routes. Handling protected routes and index and ID files are also discussed.

Workshops on related topic

React, TypeScript, and TDD
React Advanced 2021React Advanced 2021
174 min
React, TypeScript, and TDD
Top Content
Featured Workshop
Paul Everitt
Paul Everitt
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
Mastering advanced concepts in TypeScript
React Summit US 2023React Summit US 2023
132 min
Mastering advanced concepts in TypeScript
Top Content
Featured WorkshopFree
Jiri Lojda
Jiri Lojda
TypeScript is not just types and interfaces. Join this workshop to master more advanced features of TypeScript that will make your code bullet-proof. We will cover conditional types and infer notation, template strings and how to map over union types and object/array properties. Each topic will be demonstrated on a sample application that was written with basic types or no types at all and we will together improve the code so you get more familiar with each feature and can bring this new knowledge directly into your projects.
You will learn:- - What are conditional types and infer notation- What are template strings- How to map over union types and object/array properties.
Deep TypeScript Tips & Tricks
Node Congress 2024Node Congress 2024
83 min
Deep TypeScript Tips & Tricks
Top Content
Featured Workshop
Josh Goldberg
Josh Goldberg
TypeScript has a powerful type system with all sorts of fancy features for representing wild and wacky JavaScript states. But the syntax to do so isn't always straightforward, and the error messages aren't always precise in telling you what's wrong. Let's dive into how many of TypeScript's more powerful features really work, what kinds of real-world problems they solve, and how to wrestle the type system into submission so you can write truly excellent TypeScript code.
Best Practices and Advanced TypeScript Tips for React Developers
React Advanced 2022React Advanced 2022
148 min
Best Practices and Advanced TypeScript Tips for React Developers
Top Content
Featured Workshop
Maurice de Beijer
Maurice de Beijer
Are you a React developer trying to get the most benefits from TypeScript? Then this is the workshop for you.In this interactive workshop, we will start at the basics and examine the pros and cons of different ways you can declare React components using TypeScript. After that we will move to more advanced concepts where we will go beyond the strict setting of TypeScript. You will learn when to use types like any, unknown and never. We will explore the use of type predicates, guards and exhaustive checking. You will learn about the built-in mapped types as well as how to create your own new type map utilities. And we will start programming in the TypeScript type system using conditional types and type inferring.
Free webinar: Building Full Stack Apps With Cursor
Productivity Conf for Devs and Tech LeadersProductivity Conf for Devs and Tech Leaders
71 min
Free webinar: Building Full Stack Apps With Cursor
Top Content
WorkshopFree
Mike Mikula
Mike Mikula
In this webinar I’ll cover a repeatable process on how to spin up full stack apps in Cursor.  Expect to understand techniques such as using GPT to create product requirements, database schemas, roadmaps and using those in notes to generate checklists to guide app development.  We will dive further in on how to fix hallucinations/ errors that occur, useful prompts to make your app look and feel modern, approaches to get every layer wired up and more!  By the end expect to be able to run your own ai generated full stack app on your machine!
Developing Dynamic Blogs with SvelteKit & Storyblok: A Hands-on Workshop
JSNation 2023JSNation 2023
174 min
Developing Dynamic Blogs with SvelteKit & Storyblok: A Hands-on Workshop
Top Content
WorkshopFree
Alba Silvente Fuentes
Roberto Butti
2 authors
This SvelteKit workshop explores the integration of 3rd party services, such as Storyblok, in a SvelteKit project. Participants will learn how to create a SvelteKit project, leverage Svelte components, and connect to external APIs. The workshop covers important concepts including SSR, CSR, static site generation, and deploying the application using adapters. By the end of the workshop, attendees will have a solid understanding of building SvelteKit applications with API integrations and be prepared for deployment.