We have now defined all the services inside the app. The last step is to export a Runtime that combines all the services to execute the app logic.
If you want to learn more on how to structure an app with
effect, services andRuntime, check out Effect: Beginners Complete Getting Started.If you are interested specifically about React (19), see Effect with React 19: Project Template.
Since we used Effect.Service each service has a Default property containing a Layer with the service default instance.
We merge all the layers inside MainLayer:
const MainLayer = Layer.mergeAll(
WriteApi.Default,
ReadApi.Default,
Migrations.Default,
Pglite.Default
);Config provider
Remember how we used Config to define INDEX_DB in the pglite service?
export class Pglite extends Effect.Service<Pglite>()("Pglite", {
effect: Effect.gen(function* () {
const indexDb = yield* Config.string("INDEX_DB");
const client = yield* Effect.tryPromise({
try: () => _PGlite.PGlite.create(`idb://${indexDb}`),
catch: (error) => new PgliteError({ cause: error }),
});
const orm = drizzle({ client });
const query = <R>(execute: (_: typeof orm) => Promise<R>) =>
Effect.tryPromise({
try: () => execute(orm),
catch: (error) => new PgliteError({ cause: error }),
});
return { client, orm, query };
}),
}) {}When building the runtime we need to apply a valid Config to MainLayer. We do that using ConfigProvider.fromMap:
const CustomConfigProvider = Layer.setConfigProvider(
ConfigProvider.fromMap(new Map([["INDEX_DB", "v1"]]))
);We then need to provide CustomConfigProvider to MainLayer:
Make sure to not include
CustomConfigProviderin the list ofmergeAllbut instead only later as a separateLayer.provide.That's because
CustomConfigProvidermust be provided to each service in the list instead of alongside them.
const CustomConfigProvider = Layer.setConfigProvider(
ConfigProvider.fromMap(new Map([["INDEX_DB", "v1"]]))
);
const MainLayer = Layer.mergeAll(
WriteApi.Default,
ReadApi.Default,
Migrations.Default,
Pglite.Default
).pipe(Layer.provide(CustomConfigProvider));Finally, we can export a RuntimeClient using ManagedRuntime:
const CustomConfigProvider = Layer.setConfigProvider(
ConfigProvider.fromMap(new Map([["INDEX_DB", "v1"]]))
);
const MainLayer = Layer.mergeAll(
WriteApi.Default,
ReadApi.Default,
Migrations.Default,
Pglite.Default
).pipe(Layer.provide(CustomConfigProvider));
export const RuntimeClient = ManagedRuntime.make(MainLayer);When executing effects everywhere in the app we can import RuntimeClient (e.g. RuntimeClient.runPromise).
