Skip to main content
This guide will help you get started with Nile Auth and ElysiaJS. This guide outlines the steps required to configure and integrate authentication in your application.
If you have not done so yet, be sure you have obtained credentials from the console.
1

Install packages

  bun add @niledatabase/server @niledatabase/elysia elysia
2

Configure the extension

The simplest way to use Nile with Elysia is to register the plugin. This will automatically mount Nile’s default API routes (authentication, tenant management, etc.) onto your Elysia application.
app.ts
import { Elysia } from 'elysia';
import { Nile } from '@niledatabase/server';
import { nilePlugin } from '@niledatabase/elysia';

// Initialize the Nile Server
const nile = Nile({
  debug: true,
  // ... configuration options
});

const app = new Elysia().use(nilePlugin(nile));

// The plugin has now registered routes like:
// POST /api/auth/signin
// POST /api/auth/signup
// GET  /api/auth/session
// ...and more

app.listen(3000);

console.log(
  `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`,
);

Accessing the Nile Instance

The nilePlugin automatically decorates the Elysia context with your nile server instance. This allows you to access it directly in your handlers for database queries or custom auth logic.
app.get('/my-data', async ({ nile, request, error }) => {
  // 1. You can access the configured nile instance directly
  const headers = new Headers(request.headers);
  const tenantId = request.headers.get('X-Tenant-Id') || undefined;

  // 2. Use nile.withContext to ensure isolation
  return await nile.withContext({ headers, tenantId }, async (nileCtx) => {
    // This query will automatically apply the tenantId for the tenant-aware table
    const result = await nileCtx.db.query('SELECT * FROM my_table');
    return result.rows;
  });
});

Deriving the User

For a more idiomatic Elysia experience, you can create a derivation that extracts the authenticated user from the context.
const authApp = app.derive(async ({ nile, request }) => {
  const headers = new Headers(request.headers);
  // Use the decorated nile instance to fetch the session
  const user = await nile.withContext({ headers }, async (nileCtx) => {
    return await nileCtx.auth.getSession();
  });

  return { user };
});

authApp.get('/profile', ({ user, error }) => {
  if (!user) {
    return error(401, 'Not Authenticated');
  }
  return user;
});

Custom Auth Helpers

You can extend the derivation pattern to expose helper methods that automatically handle context, making your handlers cleaner.
// Create a plugin that derives the user and auth helpers for every request
const authPlugin = (app: Elysia) =>
  app.derive(async ({ nile, request }) => {
    // 1. Create headers from the incoming request to propagate cookies/auth
    const headers = new Headers(request.headers);

    // 2. Use the decorated nile instance to get the session
    const user = await nile.withContext({ headers }, async (nileCtx) => {
      return await nileCtx.auth.getSession();
    });

    return {
      Auth: {
        user,
        // Wrap SDK methods to automatically provide context
        signUp: async (email: string, password: string) => {
          return nile.withContext({ headers }, (c) =>
            c.auth.signUp({ email, password }),
          );
        },
        signIn: async (email: string, password: string) => {
          return nile.withContext({ headers }, (c) =>
            c.auth.signIn('credentials', { email, password }),
          );
        },
      },
    };
  });
Now you can use the plugin in your application and access Auth.user and methods directly.
app
  .use(authPlugin)
  .get('/profile', ({ Auth: { user }, error }) => {
    if (!user) {
      return error(401, 'Not Authenticated');
    }
    return user;
  })
  .post('/register', async ({ Auth, body }) => {
    const { email, password } = body as any;
    return await Auth.signUp(email, password);
  });

The Plugin

Under the hood, the elysia plugin does the following:
  1. Registers Routes: Maps Nile’s internal route handlers to Elysia’s router (e.g. app.get, app.post), exposing the full API.
  2. Decorates Context: Adds the nile server instance to the Elysia context (ctx.nile), making it available in all downstream handlers and plugins.
  3. Context Isolation: For the routes it registers, it wraps execution in nile.withContext to ensure tenant isolation and proper authentication handling.

Handlers and paths

The plugin iterates over the configured paths in the Nile Server SDK and registers them directly with your Elysia app instance. This ensures that all standard authentication and tenant management routes are available without manual configuration.