Skip to main content

Quickstart

This guide will walk you through creating your first Resolid application. You’ll learn how to set up a basic app with dependency injection, extensions, and services.
1

Install Resolid

First, create a new project directory and install the core package:
mkdir my-resolid-app
cd my-resolid-app
npm init -y
Install @resolid/core:
npm install @resolid/core
Make sure you’re using Node.js version 22.13.0 or 24+.
2

Create your first service

Create a simple logging service. In a new file src/services/log.ts:
// src/services/log.ts
export class LogService {
  log(message: string): void {
    console.log(`[LOG]: ${message}`);
  }
  
  error(message: string): void {
    console.error(`[ERROR]: ${message}`);
  }
}
This service will be managed by Resolid’s dependency injection container.
3

Create an extension

Extensions are reusable modules that add functionality to your app. Create src/extensions/log.ts:
// src/extensions/log.ts
import { type Extension } from "@resolid/core";
import { LogService } from "../services/log";

export const logExtension: Extension = {
  name: "log",
  providers: [
    {
      token: LogService,
      factory: () => new LogService(),
    }
  ],
  bootstrap: async (context) => {
    // This runs when the app starts
    context.emitter.on("app:ready", () => {
      const log = context.container.get(LogService);
      log.log("Application is ready!");
    });
  }
};
Extensions can register services (providers) and run initialization code (bootstrap).
4

Create your application

Now create your main application file src/index.ts:
// src/index.ts
import { createApp } from "@resolid/core";
import { logExtension } from "./extensions/log";
import { LogService } from "./services/log";

async function main() {
  // Create the app with configuration
  const app = await createApp({
    name: "my-app",
    debug: true,
    timezone: "UTC",
    extensions: [logExtension],
    expose: {
      log: LogService  // Expose LogService on app.$
    }
  });
  
  // Access the exposed service
  app.$.log.log("Hello from Resolid!");
  
  // Run bootstrap functions
  await app.run();
  
  // Use services
  app.$.log.log("App is running");
  
  // Clean up when done
  process.on("SIGINT", async () => {
    app.$.log.log("Shutting down...");
    await app.dispose();
    process.exit(0);
  });
}

main().catch(console.error);
5

Add TypeScript configuration

Create a tsconfig.json file:
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "lib": ["ES2022"],
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}
6

Add build scripts

Update your package.json:
{
  "name": "my-resolid-app",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsc && node dist/index.js"
  },
  "dependencies": {
    "@resolid/core": "latest"
  },
  "devDependencies": {
    "typescript": "^5.9.3"
  }
}
7

Run your application

Build and run your app:
npm run dev
You should see:
[LOG]: Hello from Resolid!
[LOG]: Application is ready!
[LOG]: App is running
Press Ctrl+C to stop the app and see the shutdown message.

What you built

You just created a Resolid application with:
  • Dependency injection: Services are registered and resolved automatically
  • Extensions: Modular code organization with the logExtension
  • Lifecycle management: Bootstrap functions run on startup
  • Type safety: Full TypeScript support with exposed services on app.$
  • Event system: Communication between extensions via events

Add more functionality

Let’s extend the app with a user service that depends on the log service.

Create a user service

// src/services/user.ts
import { inject } from "@resolid/core";
import { LogService } from "./log";

export class UserService {
  private logger: LogService;
  
  constructor() {
    this.logger = inject(LogService);
  }
  
  createUser(name: string): { id: string; name: string } {
    this.logger.log(`Creating user: ${name}`);
    const user = { id: Math.random().toString(36), name };
    this.logger.log(`User created with ID: ${user.id}`);
    return user;
  }
  
  getUser(id: string): { id: string; name: string } | null {
    this.logger.log(`Fetching user with ID: ${id}`);
    return null; // Simplified for demo
  }
}

Create a user extension

// src/extensions/user.ts
import { type Extension } from "@resolid/core";
import { UserService } from "../services/user";

export const userExtension: Extension = {
  name: "user",
  providers: [
    {
      token: UserService,
      factory: () => new UserService(),
    }
  ]
};

Update your app

// src/index.ts
import { createApp } from "@resolid/core";
import { logExtension } from "./extensions/log";
import { userExtension } from "./extensions/user";
import { LogService } from "./services/log";
import { UserService } from "./services/user";

async function main() {
  const app = await createApp({
    name: "my-app",
    debug: true,
    extensions: [
      logExtension,
      userExtension  // Add the user extension
    ],
    expose: {
      log: LogService,
      users: UserService  // Expose UserService
    }
  });
  
  await app.run();
  
  // Use the user service
  const user = app.$.users.createUser("Alice");
  app.$.log.log(`Created: ${JSON.stringify(user)}`);
  
  process.on("SIGINT", async () => {
    await app.dispose();
    process.exit(0);
  });
}

main().catch(console.error);
Run it again:
npm run dev
Output:
[LOG]: Application is ready!
[LOG]: Creating user: Alice
[LOG]: User created with ID: abc123
[LOG]: Created: {"id":"abc123","name":"Alice"}

Next steps

Core concepts

Learn about the application lifecycle and architecture

Dependency injection

Master the DI container and advanced patterns

Extensions

Build reusable extensions for your apps

Modules

Explore caching, logging, and database modules

Full example

Here’s the complete working example:
src/services/log.ts
export class LogService {
  log(message: string): void {
    console.log(`[LOG]: ${message}`);
  }
  
  error(message: string): void {
    console.error(`[ERROR]: ${message}`);
  }
}
src/services/user.ts
import { inject } from "@resolid/core";
import { LogService } from "./log";

export class UserService {
  private logger: LogService;
  
  constructor() {
    this.logger = inject(LogService);
  }
  
  createUser(name: string): { id: string; name: string } {
    this.logger.log(`Creating user: ${name}`);
    const user = { id: Math.random().toString(36), name };
    this.logger.log(`User created with ID: ${user.id}`);
    return user;
  }
}
src/extensions/log.ts
import { type Extension } from "@resolid/core";
import { LogService } from "../services/log";

export const logExtension: Extension = {
  name: "log",
  providers: [
    {
      token: LogService,
      factory: () => new LogService(),
    }
  ],
  bootstrap: async (context) => {
    context.emitter.on("app:ready", () => {
      const log = context.container.get(LogService);
      log.log("Application is ready!");
    });
  }
};
src/extensions/user.ts
import { type Extension } from "@resolid/core";
import { UserService } from "../services/user";

export const userExtension: Extension = {
  name: "user",
  providers: [
    {
      token: UserService,
      factory: () => new UserService(),
    }
  ]
};
src/index.ts
import { createApp } from "@resolid/core";
import { logExtension } from "./extensions/log";
import { userExtension } from "./extensions/user";
import { LogService } from "./services/log";
import { UserService } from "./services/user";

async function main() {
  const app = await createApp({
    name: "my-app",
    debug: true,
    extensions: [logExtension, userExtension],
    expose: {
      log: LogService,
      users: UserService
    }
  });
  
  await app.run();
  
  const user = app.$.users.createUser("Alice");
  app.$.log.log(`Created: ${JSON.stringify(user)}`);
  
  process.on("SIGINT", async () => {
    await app.dispose();
    process.exit(0);
  });
}

main().catch(console.error);

Build docs developers (and LLMs) love