Skip to main content

How it works

Gaudi's declarative syntax allows developers to focus on what needs to be done, instead of how. This approach allows Gaudi to understand the intention behind your code. Because of that, it can produce optimal code for you and automate a lot of the work around it. Things like logging, error handling, documentation, full stack type safety, optimized database queries, ... all are generated by Gaudi according to your descriptions.


Gaudi consists of three main parts: compiler, runtime, CLI.


Gaudi compiler handles the "declarative programming language" part. It's job is to read all your Gaudi source files, validate them, report any errors and compile a so called application "definition". This "definition" is a description, a set of instructions, for running your application.


Gaudi runtime handles the "run application" part. Runtime takes the "definition" created by the compiler, configures application endpoints, actions, validations, database connection, custom hooks, integrations, logging, ..., everything you've described in your Gaudi source files, and runs it.


CLI is an interactive command line tool that is the entrypoint for all Gaudi parts. Use it to compile your app, to run it, to sync and populate your development database, to migrate your production database, ...

Here is a simple schematic diagram of Gaudi's architecture

Gaudi Architecture Diagram

Gaudi architecture diagram

First application

Let's walk through some of Gaudi's basic concepts by describing a simple book reviews application. This is not a full tutorial with all the details, just a conceptual walkthrough. You can find detailed tutorials in our tutorials section.

Create a model

As for any other application, let's start with models.

Gaudi model language is designed to be very intuitive and database agnostic. The idea is to worry about describing your models and relationships between them instead of database details.

model Author {
field name { type string }

relation books { from Book, through author }

model Book {
reference author { to Author }

field title { type string }
field summary { type string }

We've created two related models, Author and Book. These models correspond to database tables, fields correspond to table columns, and references correspond to foreign keys. These are standard database concepts, only written in a nicer way.


Gaudi models support advanced relationship modeling techniques using computed, query and hook properties. You can read more at Core concepts > Models.

Expose an API

Now that we have models in place, we need to expose the underlying data to our clients and users; in other words, we need to create an API.

Gaudi uses a concept of entrypoints which represent a group of endpoints and operations on a single resource, e.g. a model or a relation.

api {
// operations on `Author` model
entrypoint Author {
// define CRUD endpoints
// GET /api/author/<id>
get endpoint {}
// GET /api/author
list endpoint {}
// POST /api/author
create endpoint {}
// PATCH /api/author/<id>
update endpoint {}
// DELETE /api/author/<id>
delete endpoint {}

// ... entrypoint on `Book` model

We've created 5 standard REST CRUD endpoints on each of our models in only a few lines of code (if we ignore the comments :)). And that's it, we have defined our entire API.


We've described our simple application and we're ready to run it. Since Gaudi is a language after all, we need a compiler to convert it into something "runnable". We can run Gaudi compiler using Gaudi CLI tool

npx gaudi build

Read more on compiling Gaudi apps here.


Now we're ready to run our application. Again, we need a tool from Gaudi's toolkit called runtime and we can use it via Gaudi CLI

npx gaudi start

Voila! We should have our database created and our endpoints ready to handle requests.

But, our database is empty. Wouldn't it be great if we could populate our database automatically, without having to do it manually each time we recreate our database?

Populate with data

Gaudi toolkit has another tool just for that purpose and it's called populator. We use similar syntax we've used to describe our API to populate it with some data.

// populator named "Dev"
populator Dev {
// populate Author model
populate Author as author {
// repeat 15 times
repeat as aIter 15

// we can reference iterator using it's alias "aIter"
set name "Author #" + stringify(aIter.current)

// populate Book model
// using `book` relation to created related records
populate books {
// repeat 2 times - for EACH author
repeat as bIter 2

// set fields
set title "Book title #" + stringify(bIter.current)
set summary "Summary of book #" + stringify(bIter.current) + " by " +

Now we can run this populator each time we change our database and have our database populated.

We can have as many populators as we like. For example, we can have a simple for development, one strict for testing and one randomized with real world data for presentations. Don't let your database be empty ever again!

Custom code

Declarative approach is great when it comes to using well known concepts and best practices for building most of our application. But every once in a while we simply need to resort to custom imperative code (e.g. cryptography, payment, external tools and services, our own custom behavior, ...). This is where Gaudi hooks jump in. They are the "escape hatches" which allow you to resort to any custom code or library you need and make sure it all runs happily inside Gaudi.

Gaudi also supports expressions which allow custom data manipulations (e.g. string manipulation, number calculations, ...) while still staying in Gaudi's controlled environment.

Next steps

What's next? We recommend that you read Core concepts first to get a better understanding of Gaudi basics. Then head for our tutorials sections and pick some hands-on examples you can build on your own. For any further questions and deep dives please consult our advanced topics and language reference section.

We're sure you'll quickly have a ton of other questions and suggestions that we haven't thought of or haven't got around to put them in writing. That's where you come in! ;) Ask us, open an issue or event better, open a PR. :)

Happy coding!