Elysia

repository·main·Indexed 12 days ago

https://github.com/elysiajs/elysia

An ergonomic, high-performance TypeScript web framework optimized for the Bun runtime. Elysia focuses on end-to-end type safety, developer productivity, and WinterCG compliance, featuring a unified type system for runtime validation and documentation. It provides built-in support for WebSockets, GraphQL, and a frontend RPC connector, with adapters available for Bun, Cloudflare Workers, and other Web Standard environments.

Tokens
19.2K
Snippets
80
Records
96
Agent score
96%

What's inside Elysia

  1. Overview of Elysia features

    main

    Elysia is a TypeScript-first web framework designed for high performance and exceptional developer experience, specifically optimized for the Bun runtime. Key features include:

    • End-to-End Type Safety: Provides type integrity similar to tRPC, ensuring your frontend and backend stay in sync.
    • High Performance: Optimized for Bun, significantly faster than frameworks like Express.
    • Unified Type System: A single source of truth for TypeScript types, runtime validation, and documentation.
    • Frontend RPC Connector: Enables seamless communication between client and server with full type safety.
    • WinterCG Compliance: Adheres to web standards for better compatibility.
    • GraphQL Support: Fully type-safe GraphQL implementation.
  2. Create a new Elysia application

    main

    You can quickly scaffold a new Elysia project using the Bun CLI. This sets up a new application directory with the necessary configuration to start building immediately.

    bun create elysia app
  3. Understand the Elysia Hook Lifecycle

    main

    Elysia uses a lifecycle-based hook system to intercept requests and responses at various stages. When defining hooks (either globally or locally), you can use the following lifecycle stages:

    • parse: Define how the request body is parsed (e.g., json, text, formdata).
    • transform: Transform the context value.
    • beforeHandle: Execute logic before the main route handler.
    • afterHandle: Execute logic after the main route handler.
    • mapResponse: Transform the response before it is sent.
    • afterResponse: Execute logic after the response has been sent to the client.
    • error: Catch and handle errors occurring during the lifecycle.

    Hooks can be applied globally to the entire Elysia instance or locally to specific routes/groups.

  4. Understand the Elysia Lifecycle Hooks

    main

    Elysia provides a series of lifecycle hooks that allow you to intercept and transform requests and responses. These hooks are organized within the LifeCycleStore.

    Common lifecycle events include:

    • start: Triggered when the server starts.
    • request: Triggered on every incoming request.
    • parse: Triggered during body parsing.
    • transform: Triggered during data transformation.
    • beforeHandle: Triggered before the main route handler.
    • afterHandle: Triggered after the main route handler.
    • mapResponse: Triggered to transform the response.
    • afterResponse: Triggered after the response has been sent.
    • error: Triggered when an error occurs.
    • stop: Triggered when the server is stopping.
  5. Access request data via the Context object

    main

    In Elysia, every handler receives a Context object containing the incoming request data and tools to manipulate the response. Key properties include:

    • body: The parsed request body.
    • query: The parsed URL query parameters.
    • params: The route parameters (e.g., from :id in the path).
    • headers: The incoming HTTP headers.
    • cookie: An object containing cookies, where each cookie is a Cookie instance.
    • path: The actual path extracted from the incoming URL (e.g., /id/9).
    • route: The path as registered in the router (e.g., /id/:id).
    • request: The raw standard Request object.

    When using derive, resolve, or decorator, these properties are merged into the Context object, allowing you to access custom properties alongside standard request data.

  6. Transform data during validation with Decode and Encode

    main

    Elysia allows you to transform data as it is decoded (from input to schema) and encoded (from schema to output) using the Decode and Encode methods on the transform builder.

    Workflow

    1. Decode: Converts the raw input into the type expected by the schema.
    2. Encode: Converts the validated schema output back into a format suitable for the response/output.

    This is useful for converting strings to numbers, parsing dates, or wrapping objects.

    API

    • Decode<U, D>(decode: TransformFunction): Sets the decoding logic.
    • Encode<E>(encode: TransformFunction): Sets the encoding logic.
    // Conceptual usage of the transform builder
    const schema = t.String().Decode(val => val.trim()).Encode(val => val.toUpperCase());
  7. Understand Sucrose Inference

    main

    Sucrose is an engine used by Elysia to perform static analysis on handler functions. It inspects the function's parameters and body to determine which parts of the request context (like body, query, or headers) are being accessed. This information is used to optimize the framework's execution.

    An Inference object tracks the following boolean properties:

    • query: Access to query parameters.
    • headers: Access to request headers.
    • body: Access to the request body.
    • cookie: Access to cookies.
    • set: Access to the response setter.
    • server: Access to the server instance.
    • route: Access to route information.
    • url: Access to the URL.
    • path: Access to the request path.
  8. Initialize an Elysia server

    main

    The Elysia class is the main entry point for creating a web server. You can instantiate it with an optional configuration object. By default, it uses the BunAdapter if running in a Bun environment, otherwise it falls back to the WebStandardAdapter.

    import { Elysia } from 'elysia'
    
    new Elysia()
        .get("/", () => "Hello")
        .listen(3000)
  9. Use the Cloudflare Worker adapter

    main

    To run an Elysia application on a Cloudflare Worker, use the CloudflareAdapter. When using this adapter, you must export the Elysia instance as the default export instead of calling .listen(), as Cloudflare Workers do not support the listen method. The adapter is built on top of the WebStandardAdapter but includes specific handling for Cloudflare's environment and 404 error responses.

    import { Elysia } from 'elysia'
    import { CloudflareAdapter } from 'elysia/adapter/cloudflare-worker'
    
    const app = new Elysia({
    	  adapter: CloudflareAdapter,
    })
    	  .get('/', () => 'Hello Elysia')
    	  .compile()
    
    export default app
  10. Extend custom error types for schema validation

    main

    You can augment the ElysiaTypeCustomErrors interface to add custom error keys to your schemas. This allows for better autocomplete and structured error handling when using the error option in SchemaOptions.

    To implement this, declare a module augmentation for elysia/type-system/types:

    import { ElysiaTypeCustomErrors } from 'elysia'
    
    declare module 'elysia/type-system/types' {
      interface ElysiaTypeCustomErrors {
        myPlugin: 'my.plugin.error' | `my.plugin.${string}`
      }
    }
    
    // Now you can use the custom error key in your schema
    const schema = t.String({ error: 'my.plugin.hello' } as any)
    declare module 'elysia/type-system/types' {
      interface ElysiaTypeCustomErrors {
        myPlugin: 'my.plugin.error' | `my.plugin.${string}`
      }
    }
    
    const schema = t.String({ error: 'my.plugin.hello' } as any)
  11. Configure Elysia instance options via ElysiaConfig

    main

    When initializing an Elysia instance, you can provide an ElysiaConfig object to control core behavior. Key configuration options include:

    • adapter: The server adapter to use (defaults to BunAdapter).
    • prefix: A path prefix for all routes in the instance.
    • name: A unique name for the instance, used for debugging and plugin deduplication.
    • seed: A seed for generating checksums used in plugin deduplication.
    • serve: Partial configuration for the underlying Bun server.
    • detail: OpenAPI documentation decoration.
    • tags: OpenAPI tags for the instance routes.
    • precompile: Controls Ahead of Time (AOT) compilation. Can be a boolean or an object specifying compose or schema compilation.
    • aot: Enables Ahead of Time compilation for significant performance gains at the cost of startup time.
    • strictPath: Whether to tolerate trailing slashes or enforce strict path matching.
    • websocket: Override Bun's default websocket configuration.
    • cookie: Configuration for cookies, including a sign option to specify cookie names to be signed globally.
    • analytic: Enables detailed dependency information capture.
    • encodeSchema: If true, schemas with t.Transform will call Encode before sending the response.
    • normalize: Controls value coercion for incoming/outgoing bodies. Options: true (default), false, 'exactMirror', or 'typebox'. Note: Only works with Elysia schemas, not Standard Schema.
    • nativeStaticResponse: Enables Bun's native static response handling.
    • systemRouter: Uses the runtime/framework provided router if available.
    • sanitize: Callback functions to transform string values in schemas (requires normalize: 'exactMirror').
    • allowUnsafeValidationDetails: Allows unsafe validation details in 422 error responses (use with caution in production).
    // Example configuration usage
    new Elysia({
      name: 'my-api',
      prefix: '/api',
      precompile: true,
      normalize: 'exactMirror',
      cookie: {
        sign: ['session', 'auth']
      }
    })
  12. Configure Bun server options via .listen()

    main

    When calling .listen(), you can provide an options object to configure the underlying Bun server. Common configuration keys include:

    • port: The port number to listen on.
    • development: Boolean indicating if the server is in development mode (defaults to !isProduction).
    • reusePort: Whether to reuse the port.
    • idleTimeout: Idle timeout in seconds.
    • websocket: An object to configure WebSocket specific settings.
    • fetch: The fetch handler (usually managed by Elysia).

    You can also provide custom routes via app.config.serve.routes or through the options object in .listen() to augment the server's routing capabilities.

    app.listen({
      port: 3000,
      development: true,
      websocket: {
        // WebSocket specific options
      }
    })