# TypeDB 3.12 is Now on Layerbase

> TypeDB 3.12 landed this week with a given stage for injection-safe batch queries, @doc and @meta schema annotations, a new bulk loader, and an admin service that is off by default. You can spin one up free on Layerbase in seconds.

Published: 2026-07-09
Canonical: https://layerbase.com/blog/typedb-3-12-on-layerbase

Short version: TypeDB 3.12 is what Layerbase hands you when you create a TypeDB database, and TypeDB is on the free plan, so a 3.12 instance costs nothing. The features that change how you write TypeQL are the `given` stage, which binds typed input rows that travel separately from the query string and is therefore injection-safe by construction, and the `@doc` and `@meta` annotations, which you can read back with `get_meta()`. There is also a standalone `typedb loader` for bulk imports, and the local admin service is now off by default. Databases already on 3.8 or 3.11 do not move.

The TypeDB team [shipped 3.12 on July 6](https://github.com/typedb/typedb/releases/tag/3.12.0), and it's already the version Layerbase hands you when you create a TypeDB database. TypeDB is on the free plan, so you can have a 3.12 instance running in the time it takes to read this post.

3.12 is a solid release. Most of it is the kind of work that doesn't make a headline (schema commits on a 21k-type schema went from 40 seconds to about 9, RocksDB memory is now tunable and bounded), but a few features change how you actually write TypeQL. Those are the ones worth your time.

## The `given` stage: parameters, done right

This is my favorite thing in 3.12. TypeQL now has a `given` stage that binds typed inputs to a query, and the input rows travel _separately from the query string_.

That last part matters for two reasons. First, it's injection-safe by construction. You are not concatenating a user's email into a query and hoping you escaped it correctly, because the value never touches the query text. Second, you can hand the same query many rows at once and run them in a single round trip, which skips the per-query network and compile overhead you'd pay running them one at a time.

Here's a batch insert with the Python driver against a Layerbase instance. The query declares two parameters, and the rows arrive as data:

```python
from typedb.driver import (
    TypeDB, Credentials, DriverOptions, DriverTlsConfig, TransactionType,
)

with TypeDB.driver(
    "your-host.cloud.layerbase.dev:1729",
    Credentials("admin", "your-password"),
    DriverOptions(DriverTlsConfig.enabled_with_native_root_ca()),
) as driver:
    with driver.transaction("signups", TransactionType.WRITE) as tx:
        tx.query(
            "given $email: string, $plan: string;"
            " insert $u isa user, has email == $email, has plan == $plan;",
            given_rows=[
                {"email": "ada@example.com", "plan": "pro"},
                {"email": "grace@example.com", "plan": "free"},
                {"email": "linus@example.com", "plan": "pro"},
            ],
        ).resolve()
        tx.commit()
```

Read them back and all three are there:

```text
ada@example.com -> pro
grace@example.com -> free
linus@example.com -> pro
```

Three inserts, one query, no string building. If you've ever written a loop that fires one insert per iteration, this is the thing that replaces it.

(For the exact way each driver passes rows, check the [TypeDB driver docs](https://typedb.com/docs/home/install/drivers/). The console can parse a `given` query, but it can't supply the rows, so this one is a driver feature.)

## `@doc` and `@meta` annotations

Schemas grow, and the person reading yours in a year might be you. 3.12 lets you attach `@doc("...")` docstrings and arbitrary `@meta("key", "value")` pairs to types and to their capabilities (`owns`, `plays`, `relates`, `sub`). The annotations live in the schema itself, so they survive and travel with it.

```typeql
transaction schema catalog

define
  attribute name, value string;
  attribute price, value double;
  entity product
    @doc("a sellable item in the catalog")
    @meta("icon", "box.png"),
    owns name @doc("display name shown to customers"),
    owns price;

commit
```

`@doc` is documentation for humans. `@meta` is for machines: a UI hint, an owning team, a source system, whatever your tooling wants to read back. And you _can_ read it back, with the new `get_meta()` function:

```typeql
transaction read catalog

match
  $t label product;
  let $icon = get_meta("icon", $t);
select $icon;
```

```text
   -----------
    $icon | "box.png"
   -----------
Finished. Total answers: 1
```

Dump the schema afterward and the annotations are right there on the type, so a UI that renders `product` can ask the database how to draw it instead of hardcoding a map on the client.

## A bulk loader and a quieter admin service

Two more that are worth knowing about.

**`typedb loader`.** 3.12 introduces a standalone bulk-import tool, invoked as `typedb loader`, for getting large datasets into a database faster than a stream of inserts. It's distributed separately from the core server rather than bundled into every build, so grab it from the [TypeDB release](https://github.com/typedb/typedb/releases/tag/3.12.0) when you have a real dataset to move, then point it at your endpoint. If you're just kicking the tires, the `given` batch inserts above are plenty.

**Admin service off by default.** TypeDB's local admin tool (the thing that can reset the admin password) moved off the network and onto an OS socket, and it's now disabled unless you explicitly turn it on. That's a straightforward security win: there's no admin port sitting open by default. On Layerbase this is handled for you, so it's not something you configure, but it's the kind of default I like to see a database ship.

## Quickstart on Layerbase

[Create a TypeDB database](https://cloud.layerbase.com/create?engine=typedb), then connect with the console using the details from the Quick Connect panel. Leave `--password` off and the console prompts for it, so the password stays out of your shell history and out of the process list:

```bash
typedb console --address your-host.cloud.layerbase.dev:1729 \
  --username admin
```

From there it's ordinary TypeQL:

```text
database create app

transaction schema app
define entity user, owns email; attribute email, value string;
commit

transaction write app
insert $u isa user, has email "you@example.com";
commit

transaction read app
match $u isa user, has email $e; select $e;
close
```

If you'd rather build locally first, the [Layerbase CLI](https://layerbase.com/docs/cli) (formerly SpinDB) runs the same TypeDB 3.12 on your laptop (`lbase create typedb1 -e typedb --start`, then `lbase connect typedb1`) and everything above works unchanged. ([What is the Layerbase CLI?](https://layerbase.com/docs/cli))

## Your existing databases are fine

If you already have a TypeDB database on Layerbase running 3.8 or 3.11, nothing changes. Those versions keep running exactly as they were. 3.12 is what new databases get, and moving an existing one is a decision you make, not something that happens to you.

## FAQ

### What is the `given` stage for?

Binding typed parameters to a query so the values never touch the query text. That makes it injection-safe by construction rather than by careful escaping, and it lets you hand the same query many rows at once and run them in one round trip instead of paying per-query network and compile overhead in a loop.

### Can I use `given` from the console?

The console parses a `given` query but cannot supply the rows, so this is a driver feature. Check the TypeDB driver docs for how each driver passes them.

### What is the difference between `@doc` and `@meta`?

`@doc` is documentation for the human reading your schema in a year. `@meta` is a key-value pair for machines: a UI hint, an owning team, a source system. Both attach to types and to their capabilities (`owns`, `plays`, `relates`, `sub`) and live in the schema, so they travel with it. `get_meta()` reads `@meta` back, which means a UI can ask the database how to render a type instead of hardcoding a map on the client.

### Do I need the `typedb loader` for a normal workload?

Probably not. It is a standalone bulk-import tool distributed separately from the core server, for datasets big enough that a stream of inserts is the bottleneck. For anything smaller, batch inserts through the `given` stage are plenty.

### Will my existing TypeDB database be upgraded?

No. A database on 3.8 or 3.11 keeps running exactly as it was. 3.12 is what new databases get, and moving an existing one is a decision you make rather than something that happens to you.

### Can Layerbase run a TypeDB cluster?

No. We run single-node instances, which is the right shape for development, prototypes, and plenty of small production workloads. When you need replication and failover across nodes, [TypeDB Cloud](https://typedb.com/cloud) is the managed option built for it, and your schema and queries come with you.

## Where Layerbase fits, honestly

Layerbase runs single-node TypeDB instances. That's the right shape for development, for prototypes, and for plenty of small production workloads, and on the free plan it costs nothing and sleeps when idle. What Layerbase does not do is run multi-node high-availability clusters. When you need replication and failover across nodes, [TypeDB Cloud](https://typedb.com/cloud) is the managed option built for that, from the people who build TypeDB.

The nice part is you don't have to pick early. Start free on Layerbase in seconds, learn TypeQL 3, model your domain, and if it grows into something that needs a real cluster, the schema and queries come with you.

Thanks to the TypeDB team for 3.12. The full [release notes](https://github.com/typedb/typedb/releases/tag/3.12.0) and the [TypeDB docs](https://typedb.com/docs) have the rest.
