Skip to main content
Server-side rendering (SSR) generates HTML on the server for each incoming request. This provides excellent SEO, fast initial page loads, and support for dynamic content.

Configuration

To use server-side rendering, set the mode in jaspr_options.yaml:
jaspr_options.yaml
mode: server
This tells Jaspr to generate a server executable that handles HTTP requests and renders pages dynamically.

Server Entry Point

Create a server entry point file (typically lib/main.server.dart):
import 'package:jaspr/server.dart';

void main() {
  Jaspr.initializeApp(
    options: defaultServerOptions,
  );
  
  runApp(App());
}

Initialization Options

The Jaspr.initializeApp() method accepts several configuration options:
Jaspr.initializeApp(
  // Generated options containing client component configuration
  options: defaultServerOptions,
  
  // Use isolates for rendering (better performance under load)
  useIsolates: false,
  
  // Which file extensions are allowed to be rendered
  allowedPathSuffixes: ['html', 'htm', 'xml'],
);

Server Options

The ServerOptions class (auto-generated) contains:
  • clientId: Unique identifier for the client bundle
  • clients: Map of client component types to their targets
  • styles: Function returning global styles
You should use the generated defaultServerOptions instead of creating ServerOptions manually. This is generated by the Jaspr build system.

Running the Server

Development

Start a development server with hot-reload:
jaspr serve
This starts the server and watches for file changes.

Production Build

Build a production executable:
jaspr build
This creates:
  • build/jaspr/app - The server executable
  • build/jaspr/web/ - Static assets (JS, CSS, images)

Deployment

Run the built executable:
./build/jaspr/app
The server listens on the port specified by the PORT environment variable (default: 8080):
PORT=3000 ./build/jaspr/app

Advanced Server Usage

Custom Request Handling

For advanced use cases, use serveApp() to create a custom Shelf handler:
lib/main.server.dart
import 'package:jaspr/server.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;

void main() async {
  Jaspr.initializeApp(options: defaultServerOptions);
  
  final handler = serveApp((request, render) async {
    // Custom request handling logic
    final path = request.url.path;
    
    if (path == '/api/data') {
      // Return JSON response
      return Response.ok(
        '{"message": "Hello from API"}',
        headers: {'Content-Type': 'application/json'},
      );
    }
    
    // Render component for other routes
    return render(App());
  });
  
  final server = await shelf_io.serve(handler, 'localhost', 8080);
  print('Server listening on port ${server.port}');
}

Direct Component Rendering

Render a component directly to HTML without starting a server:
import 'package:jaspr/server.dart';

Future<void> main() async {
  Jaspr.initializeApp(options: defaultServerOptions);
  
  final response = await renderComponent(
    MyComponent(),
    standalone: true, // Don't include <html>, <head>, <body>
  );
  
  print('Status: ${response.statusCode}');
  print('Body: ${String.fromCharCodes(response.body)}');
  print('Headers: ${response.headers}');
}

Server-Only Components

Some components and features are only available on the server:

AsyncStatelessComponent

Components that perform async operations during build:
import 'package:jaspr/server.dart';

class UserProfile extends AsyncStatelessComponent {
  const UserProfile({required this.userId});
  
  final String userId;
  
  @override
  Future<Component> build(BuildContext context) async {
    // Fetch user data asynchronously
    final user = await fetchUserFromDatabase(userId);
    
    return div([
      h1([.text(user.name)]),
      p([.text(user.email)]),
      img(src: user.avatar),
    ]);
  }
}

AsyncBuilder

For inline async building:
import 'package:jaspr/server.dart';

AsyncBuilder(
  builder: (context) async {
    final data = await fetchData();
    return div([.text('Data: $data')]);
  },
)
Async components are only available on the server. They will throw an error if used in client code or in static rendering without data preloading.

Document Structure

Control the HTML document structure with the Document component:
Document(
  title: 'My Page',
  lang: 'en',
  base: '/',
  charset: 'utf-8',
  viewport: 'width=device-width, initial-scale=1.0',
  meta: {
    'description': 'My awesome page',
    'keywords': 'jaspr, dart, ssr',
  },
  head: [
    link(rel: 'stylesheet', href: '/styles.css'),
    script(src: '/analytics.js', []),
  ],
  body: HomePage(),
)

Performance Optimization

Use Isolates

Enable isolate-based rendering for better performance under load:
Jaspr.initializeApp(
  options: defaultServerOptions,
  useIsolates: true, // Each request renders in a separate isolate
);
This isolates rendering work, preventing slow requests from blocking others.
Isolates add overhead for each request. Only enable this for high-traffic applications where concurrency is critical.

Middleware

Add Shelf middleware for caching, compression, and more:
import 'package:shelf/shelf.dart';
import 'package:shelf_gzip/shelf_gzip.dart';
import 'package:jaspr/server.dart';

void main() {
  ServerApp.addMiddleware(gzipMiddleware());
  ServerApp.addMiddleware(logRequests());
  
  Jaspr.initializeApp(options: defaultServerOptions);
  runApp(App());
}

Conditional Rendering

Render different content based on the request:
class App extends StatelessComponent {
  @override
  Component build(BuildContext context) {
    final url = context.binding.currentUrl;
    final isMobile = context.request?.headers['user-agent']
        ?.contains('Mobile') ?? false;
    
    return div([
      if (isMobile) MobileLayout() else DesktopLayout(),
    ]);
  }
}

API Reference

runApp()

Starts the server application:
void runApp(Component app)
Source: packages/jaspr/lib/src/server/run_app.dart:15

serveApp()

Creates a Shelf handler for custom server logic:
Handler serveApp(AppHandler handler)
Source: packages/jaspr/lib/src/server/run_app.dart:24

renderComponent()

Directly renders a component to HTML:
Future<ResponseLike> renderComponent(
  Component app,
  {Request? request, bool standalone = false}
)
Source: packages/jaspr/lib/src/server/run_app.dart:40

Next Steps

Client-Side Rendering

Learn how to add interactivity with client components

Static Site Generation

Pre-render pages for maximum performance

Build docs developers (and LLMs) love