These are the docs for 14.3, an old version of SpatialOS. 14.5 is the newest →

Schema introduction

The schema is where you define all the components that entities in your SpatialOS world can have.

For information about how to design what goes into components, see Designing components.

We also recommend reading Component best practices.

Writing .schema files

Define components in .schema files, written in schemalang. Schema files are stored in the schema/ directory.

For information how to write schema files, see the schemalang reference page.

Generating code from the schema

SpatialOS uses the schema to generate code in various languages (including C#, C++, and Java). You use this generated code in your worker code to interact with the entities in the world.

There are two ways to generate code: using the CLI, or using the schema compiler directly.

Using the CLI

To generate code, you can use the command spatial worker codegen. This will execute the build steps specified in your worker build configuration file.

Using the schema compiler directly

If you are using the flexible project layout (currently in beta), you can use the schema compiler directly.

Build dependencies

To invoke the schema compiler directly, you need the following dependencies:

  1. Schema compiler
    This is a binary which you invoke the schema compiler via CLI. Follow the steps described in Download the schema compiler.

  2. Standard schema library
    This is set of .schema files that define the standard schema library types and components, such as the improbable.Coordinates type or the improbable.Position component. Follow the steps described in Download the standard schema library. You can put the standard library schema in any directory.

Upgrading from the structured project layout to the flexible project layout

In the structured project layout, you had to:

  • specify parameters for the schema compiler in your build.json file, as an element of the tasks list, with the name Codegen.
  • put your .schema files in a directory called schema at the root of your project.

For example, given .schema files defined in the schema directory, to generate C# code into the improbable/generated directory, you would define:

  "name": "Codegen",
  "steps": [
      "name": "Dependencies",
      "arguments": [
      "name": "C#",
      "arguments": [

When you use the schema compiler directly, .schema files can exist in any directory in your project, as long as you specify it using --schema_path. To perform the same operation as above when invoking the schema compiler directly, you would run the following command:

./schema_compiler --schema_path=./schema --load_all_schema_on_schema_path --csharp_out=improbable/generated

Generating code for multiple languages

You can generate code for more than one language per invocation by specifying an output directory using the --<lang>_out argument for each language you want to generate.

For example, to generate C++ and Java code in addition to C# code for your schema, run:

./schema_compiler --schema_path=./schema --load_all_schema_on_schema_path --csharp_out=improbable/generated --java_out=improbable/generated --cpp_out=improbable/generated

Specifying schema import dependencies

You can depend on .schema files from more than one directory by specifying more than one --schema_path.

For example, if your schema is defined in the directory schema and you have downloaded the standard schema library in a directory called stl, run:

./schema_compiler --schema_path=./schema --schema_path=./stl/ --load_all_schema_on_schema_path --csharp_out=improbable/generated

Caching previously generated code

Note that the schema compiler does not use the flag --cachePath from the legacy project layout, so you can ignore it.

We recommend generating code for each .schema file individually. In other words, you should invoke the schema_compiler for each file individually instead of using the flag --load_all_schema_on_schema_path. This lets you take advantage of any caching mechanism used by your build system, as code only needs to be regenerated for .schema files that have changed.

For example, to generate C# code for the file my_schema.schema located in the schema directory, run:

./schema_compiler --schema_path=./schema --csharp_out=improbable/generated ./schema/my_schema.schema

Schema bundle generation

If you are targeting C or C++, the schema_compiler can generate additional pieces of code for you:

  • A C++ worker::Components type specialized with all of your components (and a corresponding GetAllComponents() function)
  • A C++ MakeSchemaBundle helper function that creates a worker::SchemaBundle you can use for JSON (de-)serialization of schema types
  • A set of C functions to access the binary schema bundle data (Worker_GetSchemaBundleData and Worker_GetSchemaBundleLength)

The generated worker::Components type eliminates the need to provide this type yourself. You might still want to provide it yourself if you only use a subset of your schema types and you want to limit dependencies on schema types. This can help to keep compilation times low. Alternatively, you could generate this type only for a subset of your schema files.

For JSON (de-)serialization of schema types you need access to a binary schema bundle. You have several options here. In C, pass the result of the generated Worker_GetSchemaBundleData and Worker_GetSchemaBundleLength functions to Schema_Bundle_Load. In C++, either pass those results to worker::SchemaBundle::Create or use the generated convenience function MakeSchemaBundle which does that for you. See JSON representation of Schema_ objects.

You can generate this code by invoking the schema_compiler with the --cpp_bundle_out=<dir> parameter. This generates both a C and a C++ header and source file in the specified directory which contain a couple of helper types and functions for all the .schema files you gave as input to the schema compiler. The C header file contains these declarations:

const unsigned char* Worker_Get__BUNDLE__BundleData(void);
unsigned int Worker_Get__BUNDLE__BundleLength(void);

The C++ header file contains these declarations:

namespace worker {

using __BUNDLE__Components = worker::Components<...>;

const worker::ComponentRegistry& Get__BUNDLE__Components();

SchemaBundle Make__BUNDLE__Bundle();

} // ::worker

__BUNDLE__ is replaced with the bundle name you specified using the --cpp_bundle_name=<name> parameter. Note that this has to be a valid C++ identifier. The default name is Schema. Changing the name is useful if you want to generate these helpers for multiple subsets of your schema.

You can control the base name of the generated header and source file with the --cpp_bundle_file_name=<name> parameter. --cpp_source_extension=<extension> controls the C++ source file’s extension.

The generated C++ header file expects include files for all supplied .schema files to be available on the include path. That means you have to run --cpp_out code generation for all schema files that you want to include in the bundle in a separate pass and specify the same --schema_path in both passes.

Note that using this feature prevents you from using the benefits of caching to a certain degree, because you always need to regenerate the bundle when one of the .schema files changes. In some use cases it could make sense to split up your C++ schema bundle into two or more bundles, for example to separate schema types that change often from those that are stable, to keep compilation times low.

Schema compiler CLI reference

You can call the schema compiler with these arguments:

./schema_compiler --schema_path=... [arguments] input_files

where input_files is the list of one or more .schema files that you would like to compile.

Note: When compiling with the schema standard library, ensure the schema_path is set to the directory containing the ‘improbable’ directory (where the ‘improbable’ directory contains the standard library schema).

Argument Description
--schema_path=<path_to_directory> Root path where the schema files you want to compile are stored. This flag can be specified more than once to provide multiple directories. Note, the directory must be set to the root of import paths for schema imports to resolve correctly. For example, if you have the statement import "example/player.schema", you must pass a schema path to the location of example for it to be resolved correctly.
--load_all_schema_on_schema_path Loads all schema files in the path as if each .schema file in the schema_path was passed in individually. If there are some files on the schema path that you don’t want to compile, you might want to avoid this - for example, if your build system supports caching and you want to generate only one file per invocation of the schema compiler.
--print_components Prints the components in your schema on the standard output as they are generated
--dependency_out=<path_to_file> Dumps the dependencies to a file
--ast_json_out=<path_to_directory> Dumps the AST in JSON format in a directory
--ast_prot_out=<path_to_directory> Dumps the AST in binary protobuf format in a directory
--bundle_out=<path_to_file> Generates a binary schema bundle in the specified file
--bundle_json_out=<path_to_file> Generates a JSON schema bundle in the specified file
--cpp_out=<path_to_directory> Generates C++ code from the schema to a directory
--csharp_out=<path_to_directory> Generates C# code from the schema to a directory
--java_out=<path_to_directory> Generates Java code from the schema to a directory
--descriptor_set_out=<path_to_directory> Generates a protobuf descriptor file, used internally by the Runtime
--cpp_source_extension=<extension> Generated C++ source files have this extension. Default is *.cc
--cpp_bundle_out=<dir> Generates both a C and a C++ header and source file containing schema bundle helper types and functions.
--cpp_bundle_file_name=<name> Files generated with the --cpp_bundle_out parameter have this filename. Default is cpp_bundle.
--cpp_bundle_name=<name> Name of the schema bundle. Used as a fragment in type and function names. This must be a valid C++ identifier. Default is Schema. Used with --cpp_bundle_out.

Using the generated code

For details on how to use the generated code to send and receive component updates, see the docs for your SDK:

Search results

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums