Inertia Dart
Build single page apps without building an API. This package implements the
server-side Inertia protocol for Dart and provides property helpers, SSR
support, and testing utilities. Pair it with a client adapter like
@inertiajs/react, @inertiajs/vue3, or @inertiajs/svelte.
New here? Follow the Build a Contacts App tutorial for a hands-on walkthrough using just
dart:io.
Using Serinus? Use the
serinus_inertiapackage for a more integrated experience — it providesInertiaModule,RequestContext.inertia(), and managed SSR support out of the box.
Install
dart pub add inertia_dart
| Inertia.js client version | inertia_dart package version |
|---|---|
| 3.x | >=1.0.0 |
<3.0 |
<1.0.0 |
CLI
Scaffold a Vite client with Inertia already wired:
dart run inertia_dart:inertia create my-app --framework react
Install Inertia into an existing Vite project:
dart run inertia_dart:inertia install --framework react --path ./web
Quickstart
Create a page payload and return an Inertia JSON response from your server handler.
import 'package:inertia_dart/inertia_dart.dart';
final context = PropertyContext(headers: requestHeaders);
final page = InertiaResponseFactory().buildPageData(
component: 'Dashboard',
props: {
'user': {'name': 'Ada'},
'stats': LazyProp(() => loadStats()),
},
url: '/dashboard',
context: context,
version: '1.0.0',
);
final response = InertiaResponse.json(page);
For working server/client samples, see:
Props
Property helpers let you control when data resolves and how it merges.
LazyPropandOptionalPropare excluded from the first load and only resolve on partial reloads.DeferredPropdefers evaluation until the client requests the group.MergePropsupports deep merge, append/prepend paths, and match-on keys.ScrollPropadds pagination metadata for infinite scroll behavior.OncePropadds once metadata with optional TTL and keys.
final props = {
'user': () => user,
'stats': OptionalProp(() => expensiveStats()),
'feed': DeferredProp(() => loadFeed(), group: 'feed', merge: true)
.append('items', 'id'),
'cursor': ScrollProp(() => pageData),
'token': OnceProp(() => token, ttl: Duration(hours: 1)),
};
Partial Reloads
The request helpers parse advanced Inertia headers:
X-Inertia-Partial-DataX-Inertia-Partial-ExceptX-Inertia-ResetX-Inertia-Except-Once-PropsX-Inertia-Infinite-Scroll-Merge-IntentX-Inertia-Error-Bag
Use InertiaHeaderUtils or InertiaRequest to build the correct
PropertyContext for your server.
History Flags
PageData supports history flags:
encryptHistoryclearHistory
Middleware
Enable history encryption for every response with the built-in middleware:
final middleware = EncryptHistoryMiddleware();
final response = await middleware.handle(request, (req) async {
return next(req);
});
SSR
Use SsrGateway to call your SSR server and render HTML:
final gateway = HttpSsrGateway(Uri.parse('http://localhost:13714'));
final ssr = await gateway.render(jsonPage);
Control SSR behavior in code with InertiaSsrSettings:
final settings = InertiaSsrSettings(
enabled: true,
endpoint: Uri.parse('http://127.0.0.1:13714/render'),
bundle: 'bootstrap/ssr/ssr.mjs',
runtime: 'node',
runtimeArgs: ['--trace-warnings'],
);
You can also start/stop/check a local SSR process:
final process = await startSsrServer(
SsrServerConfig.fromSettings(settings),
);
final healthy = await checkSsrServer(endpoint: settings.endpoint!);
await stopSsrServer(endpoint: settings.endpoint!);
process.kill();
CLI helpers for SSR bundles:
dart run inertia_dart:inertia ssr:start --runtime node
dart run inertia_dart:inertia ssr:check --url http://127.0.0.1:13714
dart run inertia_dart:inertia ssr:stop --url http://127.0.0.1:13714
Asset Manifest Helper
InertiaAssetManifest loads a Vite-style manifest.json and renders tags.
final manifest = await InertiaAssetManifest.load('client/dist/.vite/manifest.json');
final tags = manifest.renderTags('index.html', baseUrl: '/');
Vite Asset Helper
InertiaViteAssets reads a dev hot file or a production manifest and returns
script/style tags.
final assets = InertiaViteAssets(
entry: 'index.html',
hotFile: 'client/public/hot',
manifestPath: 'client/dist/.vite/manifest.json',
includeReactRefresh: true,
);
final tags = await assets.resolve();
final htmlTags = tags.renderAll();
dart:io HttpServer Helper
If you are using dart:io directly, you can build requests and write responses
without a framework wrapper.
final request = inertiaRequestFromHttp(httpRequest);
final context = request.createContext();
final page = InertiaResponseFactory().buildPageData(
component: 'Home',
props: {'title': 'Inertia + HttpServer'},
url: request.url,
context: context,
);
final response = InertiaResponse.json(page);
await writeInertiaResponse(httpRequest.response, response);
Vite Hot File Helper
The package ships a small Vite plugin to generate a public/hot file (Laravel
style).
If you want to generate the plugin file from Dart instead of copying it by hand, use:
import 'dart:io';
import 'package:inertia_dart/inertia_dart.dart';
Future<void> main() async {
await writeInertiaViteHotFilePlugin(Directory('client'));
}
That writes client/inertia_hot_file.js by default. You can also render the
source without writing a file:
final source = renderInertiaViteHotFilePlugin(
defaultHotFile: 'frontend/public/hot',
);
Then import it from your Vite config:
import { defineConfig } from 'vite'
import { inertiaHotFile } from './inertia_hot_file.js'
export default defineConfig({
plugins: [inertiaHotFile()],
})
A full template is available at assets/vite/vite.config.js.
Testing
Use AssertableInertia and InertiaTestExtensions for response assertions.
response.assertInertia((page) {
page.component('Dashboard').has('user.name');
});
Learn More
- Inertia Dart docs -- full API reference and tutorial
- Inertia core docs -- protocol specification and client adapters
serinus_inertia-- Serinus adapter withInertiaModule,RequestContext.inertia(), and managed SSR
Libraries
- inertia_dart
- Public entry point for the Inertia Dart package.