Understanding the Migration Landscape
Express has been the undisputed king of Node.js web frameworks for over a decade. Its minimalist philosophy, lightning-fast setup, and massive ecosystem made it the default choice for backend applications. However, as applications grow in complexity, the lack of architectural guidance in Express can lead to tangled codebases that are difficult to maintain, test, and scale. NestJS emerges as the natural evolution path—a framework that preserves the Node.js/Express runtime while introducing a disciplined, TypeScript-first architecture inspired by Angular. This guide walks you through migrating an Express application to NestJS in a systematic, incremental manner that minimizes risk and downtime.
Why Migrate from Express to NestJS?
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →Before diving into the technical steps, understanding the concrete benefits clarifies why this migration is worth the effort:
- Structured Architecture – NestJS enforces a modular design with clear separation of concerns using Controllers, Providers, and Modules. In Express, developers must invent their own structure, which often leads to inconsistent patterns across teams.
- TypeScript First – While Express can work with TypeScript, NestJS treats TypeScript as a first-class citizen with decorators, interfaces, and compile-time validation deeply integrated into the framework.
- Dependency Injection – NestJS provides a built-in IoC container that manages service lifetimes and dependencies automatically. In Express, you typically rely on manual wiring or third-party libraries.
- Testability – The modular architecture and dependency injection make unit testing and integration testing dramatically easier compared to manually mocking Express middleware and routes.
- Built-in Patterns – Guards, Interceptors, Pipes, and Filters provide standardized solutions for authentication, validation, transformation, and error handling that would require custom middleware in Express.
- CLI and Schematics – The NestJS CLI automates boilerplate generation, keeping developers focused on business logic rather than file scaffolding.
Key Architectural Differences to Internalize
Before writing migration code, grasp the fundamental paradigm shift. Express operates on a middleware pipeline where functions execute sequentially on the request/response objects. NestJS organizes code into discrete, composable building blocks:
- Controllers handle HTTP requests and define routes via decorators like
@Get(),@Post(),@Param(), and@Body(). - Services (Providers) contain business logic and are injectable into controllers and other services via the constructor.
- Modules group related controllers and services into cohesive units with clear import/export boundaries.
- DTOs (Data Transfer Objects) define and validate the shape of incoming data using class-validator decorators.
- Pipes transform and validate data before it reaches route handlers, replacing manual body parsing and validation middleware.
Think of the migration not as a rewrite but as a reorganization where existing Express route handlers and middleware are transplanted into NestJS constructs with clearer contracts.
Step-by-Step Migration Guide
The safest approach is an incremental migration where Express and NestJS coexist within the same project, allowing you to move routes module by module while maintaining a single deployable artifact. Here's the complete roadmap.
Step 1: Initialize the NestJS Project Inside Your Express Codebase
Begin by installing the NestJS CLI globally and generating a new project structure alongside your existing Express code. The goal is to create a NestJS scaffold that can import and gradually replace Express functionality.
npm install -g @nestjs/cli
nest new server --directory ./nestjs-app
cd nestjs-app
This creates a standard NestJS project with app.module.ts, app.controller.ts, and app.service.ts. Rather than discarding your Express code, you will keep both codebases in the same repository and let NestJS serve as the HTTP entry point, delegating to Express routes during the transition period.
Step 2: Configure NestJS to Host Existing Express Routes as Middleware
NestJS allows you to mount raw Express middleware and routers directly. This is the bridge that lets you migrate route by route without downtime. First, install the Express platform adapter if not already present:
npm install @nestjs/platform-express
Create a dedicated module that wraps your existing Express router. Suppose your current Express application defines routes in a file called legacy-routes.js:
// legacy-routes.js (existing Express code)
const express = require('express');
const router = express.Router();
router.get('/api/users', (req, res) => {
const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
res.json(users);
});
router.post('/api/users', (req, res) => {
const { name } = req.body;
res.status(201).json({ id: Date.now(), name });
});
router.get('/api/health', (req, res) => {
res.json({ status: 'ok', timestamp: Date.now() });
});
module.exports = router;
In NestJS, create a module that imports this router using the MiddlewareConsumer interface. Here's how to bridge the gap:
// legacy.module.ts
import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';
import * as legacyRouter from '../legacy-routes';
@Module({})
export class LegacyModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(legacyRouter)
.forRoutes('*'); // Mounts the Express router on all paths
}
}
Register this module in your root AppModule so NestJS passes requests through to the legacy router:
// app.module.ts
import { Module } from '@nestjs/common';
import { LegacyModule } from './legacy/legacy.module';
import { UsersModule } from './users/users.module'; // New NestJS module (migrated later)
@Module({
imports: [LegacyModule, UsersModule],
})
export class AppModule {}
At this point, your NestJS application handles all requests—those not yet migrated pass through the Express router, while new NestJS routes coexist. The application starts via NestJS's bootstrap:
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
console.log('Server running on http://localhost:3000');
}
bootstrap();
Step 3: Migrate Route Handlers to NestJS Controllers
Now begin migrating routes one by one. Pick a self-contained route group—users in this example—and create a dedicated NestJS module with controller and service.
First, generate the module using the CLI (or manually):
nest generate module users
nest generate controller users
nest generate service users
The service contains the business logic that was previously inline in Express route handlers:
// users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
interface User {
id: number;
name: string;
email: string;
}
@Injectable()
export class UsersService {
private users: User[] = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
];
findAll(): User[] {
return this.users;
}
findOne(id: number): User {
const user = this.users.find(u => u.id === id);
if (!user) {
throw new NotFoundException(`User with id ${id} not found`);
}
return user;
}
create(createUserDto: CreateUserDto): User {
const newUser: User = {
id: this.users.length + 1,
name: createUserDto.name,
email: createUserDto.email,
};
this.users.push(newUser);
return newUser;
}
update(id: number, updateUserDto: UpdateUserDto): User {
const user = this.findOne(id);
Object.assign(user, updateUserDto);
return user;
}
remove(id: number): void {
const index = this.users.findIndex(u => u.id === id);
if (index === -1) {
throw new NotFoundException(`User with id ${id} not found`);
}
this.users.splice(index, 1);
}
}
The DTOs define and validate request payloads. In Express, validation was either absent or handled manually. NestJS uses class-validator decorators:
// create-user.dto.ts
import { IsString, IsEmail, MinLength, IsNotEmpty } from 'class-validator';
export class CreateUserDto {
@IsString()
@IsNotEmpty()
@MinLength(2)
name: string;
@IsEmail()
@IsNotEmpty()
email: string;
}
// update-user.dto.ts
import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
export class UpdateUserDto extends PartialType(CreateUserDto) {}
The controller replaces Express route handlers. Notice how decorators replace router.get() and manual path definitions:
// users.controller.ts
import {
Controller,
Get,
Post,
Body,
Param,
Put,
Delete,
ParseIntPipe,
HttpCode,
HttpStatus,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.usersService.findOne(id);
}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Put(':id')
update(
@Param('id', ParseIntPipe) id: number,
@Body() updateUserDto: UpdateUserDto,
) {
return this.usersService.update(id, updateUserDto);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id', ParseIntPipe) id: number) {
this.usersService.remove(id);
}
}
The module wires everything together:
// users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
Once the NestJS Users module is fully tested, remove the corresponding route definitions from legacy-routes.js to avoid duplicate handlers. The migration of this route group is complete.
Step 4: Transform Express Middleware into NestJS Interceptors, Guards, and Pipes
Express middleware often serves multiple purposes: logging, authentication, validation, rate limiting. NestJS provides specialized constructs for each concern, making the code more intention-revealing.
Logging middleware → Interceptor: In Express, a logging middleware might look like this:
// express-logger.js
module.exports = function logger(req, res, next) {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.originalUrl} ${res.statusCode} - ${duration}ms`);
});
next();
};
In NestJS, this becomes an interceptor that wraps the execution context:
// logging.interceptor.ts
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable {
const request = context.switchToHttp().getRequest();
const start = Date.now();
return next.handle().pipe(
tap(() => {
const response = context.switchToHttp().getResponse();
const duration = Date.now() - start;
console.log(
`${request.method} ${request.originalUrl} ${response.statusCode} - ${duration}ms`,
);
}),
);
}
}
Apply it globally or at the controller level:
// main.ts (global application)
import { LoggingInterceptor } from './logging.interceptor';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new LoggingInterceptor());
await app.listen(3000);
}
Authentication middleware → Guard: An Express JWT verification middleware:
// express-auth.js
const jwt = require('jsonwebtoken');
module.exports = function auth(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ message: 'No token provided' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
return res.status(401).json({ message: 'Invalid token' });
}
};
Becomes a NestJS guard that integrates with the framework's execution pipeline:
// auth.guard.ts
import {
Injectable,
CanActivate,
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
import * as jwt from 'jsonwebtoken';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(' ')[1];
if (!token) {
throw new UnauthorizedException('No token provided');
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
request.user = decoded;
return true;
} catch (err) {
throw new UnauthorizedException('Invalid token');
}
}
}
Apply the guard using the @UseGuards() decorator:
@Controller('users')
@UseGuards(AuthGuard)
export class UsersController {
// All routes in this controller require authentication
}
Validation middleware → Pipe: Express body validation using Joi or express-validator becomes a global validation pipe in NestJS. Enable the built-in ValidationPipe globally:
// main.ts
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
await app.listen(3000);
}
With this pipe active, all DTOs decorated with class-validator rules are automatically validated. Invalid requests receive a 400 Bad Request response with detailed error messages—no manual middleware needed.
Step 5: Migrate Error Handling to NestJS Exception Filters
Express error handling typically relies on custom error middleware with four parameters:
// express-error-handler.js
module.exports = function errorHandler(err, req, res, next) {
console.error(err.stack);
const status = err.status || 500;
res.status(status).json({
message: err.message,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined,
});
};
In NestJS, exception filters catch both thrown HTTP exceptions and unhandled errors. Create a global filter that mirrors your Express error handler:
// http-exception.filter.ts
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
Logger,
} from '@nestjs/common';
import { Request, Response } from 'express';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
private readonly logger = new Logger(AllExceptionsFilter.name);
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
let status: number;
let message: string;
if (exception instanceof HttpException) {
status = exception.getStatus();
const responseBody = exception.getResponse();
message =
typeof responseBody === 'string'
? responseBody
: (responseBody as any).message || 'Internal server error';
} else {
status = HttpStatus.INTERNAL_SERVER_ERROR;
message = 'Internal server error';
}
this.logger.error(
`${request.method} ${request.url} ${status} - ${message}`,
exception instanceof Error ? exception.stack : '',
);
response.status(status).json({
statusCode: status,
message,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}
Register it globally in main.ts:
app.useGlobalFilters(new AllExceptionsFilter());
Step 6: Convert Environment Configuration
Express applications commonly use dotenv and process.env scattered throughout the codebase. NestJS offers a structured configuration module that centralizes environment variables and provides type-safe access.
npm install @nestjs/config joi
Create a configuration file that defines the expected environment shape:
// configuration.ts
export default () => ({
port: parseInt(process.env.PORT, 10) || 3000,
database: {
host: process.env.DATABASE_HOST || 'localhost',
port: parseInt(process.env.DATABASE_PORT, 10) || 5432,
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD,
name: process.env.DATABASE_NAME,
},
jwt: {
secret: process.env.JWT_SECRET,
expiresIn: process.env.JWT_EXPIRES_IN || '1h',
},
});
Load it in AppModule with schema validation:
// app.module.ts
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
import configuration from './configuration';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [configuration],
validationSchema: Joi.object({
PORT: Joi.number().default(3000),
DATABASE_HOST: Joi.string().required(),
DATABASE_PORT: Joi.number().default(5432),
DATABASE_USERNAME: Joi.string().required(),
DATABASE_PASSWORD: Joi.string().required(),
DATABASE_NAME: Joi.string().required(),
JWT_SECRET: Joi.string().required(),
JWT_EXPIRES_IN: Joi.string().default('1h'),
}),
}),
LegacyModule,
UsersModule,
],
})
export class AppModule {}
Access configuration via the injected ConfigService:
// users.service.ts
import { ConfigService } from '@nestjs/config';
@Injectable()
export class UsersService {
constructor(private configService: ConfigService) {
const dbHost = this.configService.get('database.host');
console.log(`Connected to database at ${dbHost}`);
}
}
Step 7: Migrate Database Access to TypeORM or Prisma Modules
Express apps often use raw database drivers (pg, mysql2, mongodb) with manual connection pooling. NestJS integrates with ORMs through dedicated modules that handle connection lifecycle and repository injection.
Example migration from raw pg queries to TypeORM:
npm install @nestjs/typeorm typeorm pg
Define an entity that replaces raw SQL result parsing:
// user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';
@Entity('users')
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 100 })
name: string;
@Column({ unique: true })
email: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
Register the TypeORM module in AppModule:
// app.module.ts (updated)
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
ConfigModule.forRoot({ /* ... */ }),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
type: 'postgres',
host: configService.get('database.host'),
port: configService.get('database.port'),
username: configService.get('database.username'),
password: configService.get('database.password'),
database: configService.get('database.name'),
entities: [User],
synchronize: false,
logging: true,
}),
}),
TypeOrmModule.forFeature([User]),
LegacyModule,
UsersModule,
],
})
export class AppModule {}
The service now uses the injected repository instead of raw SQL:
// users.service.ts (refactored with TypeORM)
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
import { CreateUserDto } from './dto/create-user.dto';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository,
) {}
async findAll(): Promise {
return this.userRepository.find();
}
async findOne(id: number): Promise {
const user = await this.userRepository.findOne({ where: { id } });
if (!user) {
throw new NotFoundException(`User with id ${id} not found`);
}
return user;
}
async create(createUserDto: CreateUserDto): Promise {
const user = this.userRepository.create(createUserDto);
return this.userRepository.save(user);
}
async update(id: number, updateUserDto: Partial): Promise {
const user = await this.findOne(id);
Object.assign(user, updateUserDto);
return this.userRepository.save(user);
}
async remove(id: number): Promise {
const result = await this.userRepository.delete(id);
if (result.affected === 0) {
throw new NotFoundException(`User with id ${id} not found`);
}
}
}
Step 8: Write Tests for Migrated Modules
One of the strongest motivations for migrating to NestJS is improved testability. NestJS's dependency injection allows services to be tested in isolation with mocked dependencies.
Unit test for UsersService:
// users.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
import { getRepositoryToken } from '@nestjs/typeorm';
import { User } from './user.entity';
import { Repository } from 'typeorm';
import { NotFoundException } from '@nestjs/common';
describe('UsersService', () => {
let service: UsersService;
let repository: Repository;
const mockRepository = {
find: jest.fn(),
findOne: jest.fn(),
create: jest.fn(),
save: jest.fn(),
delete: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UsersService,
{
provide: getRepositoryToken(User),
useValue: mockRepository,
},
],
}).compile();
service = module.get(UsersService);
repository = module.get>(getRepositoryToken(User));
});
afterEach(() => {
jest.clearAllMocks();
});
it('should return all users', async () => {
const mockUsers = [{ id: 1, name: 'Test', email: 'test@test.com' }];
mockRepository.find.mockResolvedValue(mockUsers);
const result = await service.findAll();
expect(result).toEqual(mockUsers);
expect(mockRepository.find).toHaveBeenCalledTimes(1);
});
it('should throw NotFoundException when user does not exist', async () => {
mockRepository.findOne.mockResolvedValue(null);
await expect(service.findOne(999)).rejects.toThrow(NotFoundException);
});
it('should create a new user', async () => {
const dto = { name: 'New User', email: 'new@example.com' };
const savedUser = { id: 3, ...dto };
mockRepository.create.mockReturnValue(dto);
mockRepository.save.mockResolvedValue(savedUser);
const result = await service.create(dto);
expect(result).toEqual(savedUser);
});
});
Controller tests are equally straightforward using the Test factory:
// users.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
describe('UsersController', () => {
let controller: UsersController;
let service: UsersService;
const mockService = {
findAll: jest.fn(),
findOne: jest.fn(),
create: jest.fn(),
update: jest.fn(),
remove: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [UsersController],
providers: [
{
provide: UsersService,
useValue: mockService,
},
],
}).compile();
controller = module.get(UsersController);
service = module.get(UsersService);
});
it('should call findAll on the service', async () => {
const users = [{ id: 1, name: 'Alice', email: 'alice@test.com' }];
mockService.findAll.mockResolvedValue(users);
expect(await controller.findAll()).toBe(users);
expect(mockService.findAll).toHaveBeenCalled();
});
});
Step 9: Remove Legacy Express Code After Full Migration
Once all route groups are migrated and verified, remove the LegacyModule from AppModule, delete the legacy-routes.js file, and uninstall any Express-specific middleware packages that are no longer needed. The application is now a pure NestJS codebase. Update the package.json scripts:
"scripts": {
"build": "nest build",
"start": "nest start",
"start:dev": "nest start --watch",
"start:prod": "node dist/main",
"test": "jest",
"test:e2e": "jest --config ./test/jest-e2e.json"
}
The final main.ts should look clean and declarative:
// main.ts (final)
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { LoggingInterceptor } from './logging.interceptor';
import { AllExceptionsFilter } from './http-exception.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
app.useGlobalInterceptors(new LoggingInterceptor());
app.useGlobalFilters(new AllExceptionsFilter());
await app.listen(process.env.PORT || 3000);
console.log(`Application running on port ${process.env.PORT || 3000}`);
}
bootstrap();
Best Practices for a Smooth Migration
- Migrate Incrementally, Not All at Once – Keep the Express router mounted while migrating one module at a time. This prevents large-scale rewrites that introduce regression bugs and block releases.
- Preserve Existing Tests During Migration – Run your Express test suite after each migration step. Once a route group moves to NestJS, write equivalent NestJS tests before removing the old tests.
- Use the Coexistence Pattern – Don't run two separate servers on different ports. Let NestJS wrap Express routes as middleware so the URL structure and port remain unchanged throughout the migration.
- Leverage the CLI Generators – Use
nest generatefor every new module, controller, service, guard, and interceptor. Consistent file structure aids team onboarding and reduces decision fatigue. - Centralize Configuration Early – Migrate environment variable handling to the
@nestjs/configmodule as one of the first steps. This provides immediate value and reduces scatteredprocess.envreferences. - Adopt DTOs and Validation Immediately – When migrating a route, always create a DTO with class-validator decorators. The automatic input validation catches bugs that manual Express validation missed.
- Handle Async Errors Properly – NestJS automatically catches async errors from controllers and services. Express requires explicit error wrapping with
next(err). Remove all manualtry/catchblocks in route handlers that existed solely for error forwarding. - Document the Migration Progress – Maintain a checklist in the project README tracking which Express routes have been migrated. This keeps the team aligned and provides a sense of progress.
- Monitor Performance – NestJS adds a thin abstraction layer over Express. In practice, the overhead is negligible, but monitor response times and memory usage during the coexistence phase to detect any regressions early.
Conclusion
Migrating from Express to NestJS is a strategic evolution rather than a disruptive overhaul. By mounting Express routers as middleware within a NestJS application, you can transition route by route, module by module, without downtime or broken functionality. The result is a codebase with clear separation of concerns, automatic input validation, dependency injection, and vastly improved testability—all while still running on the battle-tested Express platform underneath. The discipline that NestJS imposes pays dividends as your application grows: new features are added in predictable locations, onboarding new developers becomes faster, and the test suite provides genuine confidence during refactoring. Start small with a single route group, prove the pattern works in your context, and steadily work through the migration checklist until the legacy Express code is a distant memory and your NestJS application stands complete, maintainable, and ready for the future.