Skip to main content

Create a new service

Add service with cli

A service is a logical group of functions and subscriptions. This is where the domain driven aspect comes in.
In our example, we will use the classic example - Users.

At the end, we want to have two domains - User and Email.

We will need to have this functionality:

  • sign up a new user
  • get a user by email
  • send a welcome email to user

Set up a new service

First, we need to create a new service.
You can simply add a new service by using the CLI tool.

global install
purista add service

The CLI will guide you through all steps, and will create all files for your.
In the first step, you will asked for the name of our new service.
We will start with User.

? What is the name (or domain) of your new service (something like: user or account)

::: hint Service names should be short and in best case a single word - like user or email.
You can enter the name in natural way. The CLI tool will take care of casing and whitespaces.
For example, if you have a domain bank account, you can simply type in bank account. The CLI tool will convert it to something like bankAccount :::

After you have confirm your input by pressing the enter key, you will be asked for a short description of the service.

? What is the matter of service "user"

Here, you should enter some short, general description, which will be used for some human-facing documentation.
So, please provide here something like: manages data related to users.

In the last step, you will be asked for the version of your service. It defaults to 1, which you can simply confirm by pressing the enter key.
If you need to create a new version of an existing service, you can enter any integer number larger than 1.

Version number of this service (1) 

Now, all files should be generated. A list of generated files will be printed out.

βœ”  ++ /src/service/ServiceEvent.enum.ts 
βœ”  ++ /src/service/user/generalUserServiceInfo.ts
βœ”  ++ /src/service/user/v1/userV1Service.ts
βœ”  ++ /src/service/user/v1/userV1Service.test.ts
βœ”  ++ /src/service/user/v1/userV1ServiceBuilder.ts
βœ”  ++ /src/service/user/v1/index.ts
βœ”  ++ /src/service/user/v1/userServiceConfig.ts

From here, you are ready to add commands and subscriptions to the new service user.

But, for our example, please redo the steps, and create an additional service email.
You can skip the first step, if you provide the service name at the CLI call.

global install
purista add service email


PURISTA is using builders to create services. The created files are no actual service class implementation.
PURISTA creates a service builder with configurations. And the builder is able to create a service class instance, based on the configuration.


This file /src/service/ServiceEvent.enum.ts contains a typescript enum, which should contain all event names, used in the repository.
The enum will be enhanced by the CLI tool, if you add commands or subscriptions, and the response refers to an event name.


Prevent hardcoding of event names as simple strings in your code. Use this global enum instead.


This file /src/service/user/generalUserServiceInfo.ts contains the basic information for your service:

  • service name
  • service description

You only need to change the file, if you need to align the description.


This file /src/service/user/v1/userV1Service.ts only contains the registration of commands and subscriptions in the service builder. It should not contain any further service builder configurations. Any other configuration should be done in the service builder file itself.


The file /src/service/user/v1/userV1Service.test.ts, is a unit test file, which will check the final configurations in the service builder.


The /src/service/user/v1/userV1ServiceBuilder.ts file, is the initial service builder for your service. In this file, the basic service configuration will be made.
Also, the optional custom service configuration will be add here.
If you want to create a new version of a service, you can simply copy the whole service version folder and align the service version in this file.

Do not add commands or subscriptions here

because of:

  • cycling dependencies! the command and subscription builders are created by that builder
  • this is used by PURISTA to be able to deploy as FaaS


In the file /src/service/user/v1/userServiceConfig.ts, the custom service configuration can be made.

Service configurations

A custom configuration relates to your business logic and your requirements. It is not used by PURISTA itself.
The custom service config will be available in all commands and subscriptions of this service via this.config.
Custom service configurations are one option to pass configuration values to commands and subscriptions.
But, you can also use stores.

Service configuration and stores addressing different data. Here is a table, that will help you to understand the differences.

custom configConfig StoreSecret store
provided/managed byinfrastructure & deploymentdatabase or vendor solutionvendor solution
addressestechnical configurationbusiness configurationsecrets & confidential data
valueis set once, during instance creationfetched per usagefetched per usage
change effectsinstance restart/next deploymenton next usageon next usage
value typeobject (nested)object, string, number, boolean (key-value)string (key-value)
can be set ()*πŸ›‘ noβœ… yesβœ… yes
can be deleted ()*πŸ›‘ noβœ… yesβœ… yes
use for confidential dataπŸ™πŸ» please no, technically possibleπŸ™πŸ» please no, technically possibleβœ… yes
use casesthird-party url, ports, timeout settingsfeature flag, business data like currency exchange valuespasswords, auth tokens, certificates

(*) by commands and subscriptions

For a custom configuration, you must define a zod schemaopen in new window.

export const userServiceV1ConfigSchema = z.object({
  myOption: z.string().optional()

export type UserServiceV1Config = z.input<typeof userServiceV1ConfigSchema>

As you can see, in the example a string option entry myOption is added. This filed is marked as optional. Because of this, in the generated type UserServiceV1Config, the myOption is also optional.

Now, in the builder file userV1ServiceBuilder.ts in the same directory, typescript will complain on .setDefaultConfig({}).
Setting the default configuration, requires to set all root fields of the default configuration. The optional flag, only relates to the input, when you create a service instance and provide a service configuration.


PURISTA follows the pattern, to always have default values, which can be overwritten, but only when there is a actual need for it.

Because of this, you need to change it in the builder file userV1ServiceBuilder.ts.

export const userV1ServiceBuilder = new ServiceBuilder(userServiceInfo)
    myOption: 'something'

Be aware

PURISTA does not deep merge configurations! If you have nested configurations, you should be aware of.

Create a service instance

To get a real service instance, you can use the service builder from userV1Service.ts, which includes the configuration for the service with all commands and subscriptions.

To create a service instance, you need to provide at least an event bridge instance.

// get instance of user
const userInstance = userV1Service.getInstance(eventBridge)
// initiate/start the user instance
// it registers the commands and the subscriptions to the event bridge
await theService.start()

If you have a custom configuration, you can provide it like this:

const serviceConfig = {
  myOption: 'something'
// get instance of user with config
const userInstance = userV1Service.getInstance(eventBridge, { 

// which allows usage like
console.log(userInstance.config.myOption) // outputs: something


All available options can be found in ServiceBuilder API documentation

Last update:
Contributors: Sebastian Wessel