# Create a schema

## [](#_review)Review

In the previous section we’ve created our TypeDB server instance and connected TypeDB Studio (or Console).

Now we’ll use the server to create a database and initialize the schema. A TypeDB schema defines what data is permitted to be written to your database. Think of schemas as your _blueprints_ for your data (or custom _dna_ from biology, or _classes_ in OOP).

Schemas are one of the key aspects of TypeDB: they allow the database to validate inserted data, check queries for validity, and perform query optimization. TypeDB’s schemas are intuitive and built with higher-level building blocks compared to relational, document, or graph databases.

## [](#_typedbs_data_model_at_a_glance)TypeDB’s data model at a glance

Let’s have a quick look at TypeDB’s data model. In TypeDB, data is stored in **types**, which can be either:

*   **entity** types (e.g., a type of all the `user`'s in your app)
    
*   **relation** types (e.g., all the `friendship`'s of users)
    
*   **attribute** types (e.g., the `username`'s of `user`'s, or the `start_date`'s of `friendship`'s)
    

Stored data objects are called **instances** of types, and instances may connect to other instances. This simple mechanism of “connecting” underpins the distinction of entity, relation, and attribute types above.

For example, to create a relation instance we must reference multiple other entities or relations, which we call the relation’s **role players**. Similarly, to create an attribute instance we will reference a single entity or relation instances, which we call the attribute’s **owner**. Makes sense, right?

TypeDB’s data model is conceptually simple, but at the same time extremely systematic and flexible. This is what enables TypeDB’s type system to unify concepts from relational, document, and graph DBMSs, and blend them with ideas from modern strongly typed programming languages.

## [](#create_database)Database management 101

TypeDB supports operating multiple independent databases within one server.

Databases each contain their own set of schema and data. Transactions operate against one database at a time and cannot read data from multiple databases.

Databases can be created and deleted easily. Let’s create a database for this guide!

*   Studio
    
*   Console
    

First, ensure you have an active connection to TypeDB. If you don’t, all Studio pages will prompt you to connect to TypeDB using your address and credentials.

To select a database to work with, use the dropdown menu on the right of the database icon in the top toolbar. You can also create new databases here. Let’s create one called `get_started`.

Start TypeDB Console and connect to TypeDB with the following terminal command:

```bash
$ typedb console --address=<address> --username=<username>
```

You will be prompted for a password, after which the **server-level interface** of Console will be opened. To create a new database called `get_started` type the command:

```console
database create get_started
```

You can similarly delete a database with the command `database delete get_started`. To see a list of all available databases use `database list`.

## [](#_opening_a_transaction)Opening a transaction

To use a database, we must first open a transaction.

There are three types of transactions:

*   **Schema** transactions allow you to run any type of queries, including queries that modify the database schema. They are computationally expensive and should be used mostly for schema updates.
    
*   **Write** transactions allow you to execute queries that read or write data.
    
*   **Read** transactions allow you to execute queries that read data. Read transactions are the cheapest kind of transaction.
    

All TypeDB transactions use snapshotting: they will never see any other transaction’s operations. To see subsequent changes to the database, you must open a brand-new transaction.

Persisting changes to a database is done with a `commit` operation. This validates your changes, reporting any errors to you, and otherwise durably writes the data to the database.

Read transactions cannot be committed as they cannot write to the database - simply `close` them instead! Write and schema transactions can also be discarded without commit using `close`.

Let’s open a simple schema transaction and define our first type:

*   Studio
    
*   Console
    

Select your transaction type in the top bar: `schema`.

On the Query page, enter the following query:

```typeql
define entity user;
```

Click **Run query** to run your query.

Studio by default auto-commits every query. If **auto** is enabled in the top bar, then you don’t need to do anything else.

You can also control the transactions manually by changing **auto** to **manual** in the top bar.

From Console’s server-level interface, open a `schema` transaction (tip: use the kbd:\[Tab\] key to autocomplete each word!):

```console
transaction schema get_started
```

This will open a new **transaction-level interface**. In it, you will be able to run queries. You can similarly open `write` or `read` transactions.

Then, enter the following query and hit kbd\[Enter\] **twice** to submit:

```typeql
#!test[schema]
define entity user;
```

Finally, commit the transaction by typing:

```console
commit
```

A quick **tip** if you are using Console for this course. Queries on this page can be turned into runnable **Console scripts** by clicking the “hidden lines” button (![eye](../../../home/_images/svg/eye.svg)). These scripts can then be **pasted** directly into the server-level interface of Console, and run end-to-end simply by pressing kbd\[Enter\].

## [](#_defining_your_schema)Defining your schema

Let’s define a simple database schema: we want to store `user`'s and their `username`'s in our database and, in addition, let’s also permit `friendship`'s between users. TypeQL is uniquely designed so that you can simply go from your literal description of the data to writing a schema, without worrying about tables, joins, vertices or edges, or document referencing.

*   Studio
    
*   Console
    

On the Query page, select a **schema** transaction using the top bar as described above, then run these two queries.

```typeql
define
entity user, owns username;
attribute username, value string;
```

```typeql
define
relation friendship, relates friend @card(2);
user plays friendship:friend;
```

Make sure to `commit` if you’re manually controlling your transactions.

Open a schema transaction with the command `transaction schema get_started` as explained above. Then paste the following query in:

```typeql
#!test[schema]
define
entity user, owns username;
attribute username, value string;
```

Press kbd\[Enter\] twice to send the query. Similarly, send the following second query:

```typeql
#!test[schema]
define
relation friendship, relates friend @card(2);
user plays friendship:friend;
```

Finally, commit the transaction by typing `commit` and press kbd\[Enter\]. You have just defined the first few types in your database schema, congratulations!

Let us dissect the second query in a bit more detail.

*   In the first line of the query we introduce the relation type `friendship` with a `friend` **role** (in _programmer lingo_: think of a role as a **interface** that other types can implement). In the same line, we also declare that each friendship requires _exactly two friends_ when created (`card` is short for “cardinality”, and is a first example of an **annotation**. Annotations make schema statements much more specific - but more on that in a moment).
    
*   In the second line, we then define that users **can play** the role of friends in friendships (in _programmer lingo_: the type `user` **implements** the “friend-role” interface).
    

It’s worth pointing out that roles are only one of two kinds of interfaces that types may implement, the other being **ownership**: for example, in our first query above we defined that the `user` type “implements the username owner interface”. These interfaces make our life very easy as we’ll see, especially when dealing with type hierarchies!

Let’s write a few more definition queries to get a feel of database schemas in TypeDB.

*   Studio
    
*   Console
    

First, note that relation types, like entity types, are first-class definitions in our type system. In particular, they too can own attributes (and may play roles in other relation types).

For example:

```typeql
define
attribute start-date, value datetime;
friendship owns start-date @card(0..1);
```

This defines a `start-date` attribute and then declares each friendship may own a `start_date` (i.e., the type `friendship` implements the “start-date owner” interface). The definition is followed by a `@card` annotation, which specifies that friendships own _between_ zero or one start dates. In fact, this is the default cardinality, so you don’t actually need `@card` here at all.

The next query illustrates usage of “unbounded” cardinality together with another useful annotation, `@key`. This specifies that the `username` of a `user` should uniquely identify a user, i.e., it is a _key attribute_.

```typeql
define
attribute status, value string;
user owns status @card(0..);
user owns username @key;
```

Importantly, different types may own the same attributes; and, similarly, different types may play the same role of a relation type. This flexibility of connecting types is a central feature of data modeling with TypeDB. Run the next query to define an `organization` type which shares many of the interfaces of `user`:

```typeql
define
entity organization,
owns username,
owns status,
plays friendship:friend;
```

Let’s commit and move on!

First, note that relation types, like entity types, are first-class definitions in our type system. In particular, they too can own attributes (and may play roles in other relation types).

For example:

```typeql
#!test[schema]
define
attribute start-date, value datetime;
friendship owns start-date @card(0..1);
```

This defines a `start-date` attribute and then declares each friendship may own a `start_date` (i.e., the type `friendship` implements the “start-date owner” interface). The definition is followed by a `@card` annotation, which specifies that friendships own _between_ zero or one start dates. In fact, this is the default cardinality, so you don’t actually need `@card` here at all.

The next query illustrates usage of “unbounded” cardinality together with another useful annotation, `@key`. This specifies that the `username` of a `user` should uniquely identify a user, i.e., it is a _key attribute_.

```typeql
#!test[schema]
define
attribute status, value string;
user owns status @card(0..);
user owns username @key;
```

Importantly, different types may own the same attributes; and, similarly, different types may play the same role of a relation type. This flexibility of connecting types is a central feature of data modeling with TypeDB. Run the next query to define an `organization` type which shares many of the interfaces of `user`:

```typeql
#!test[schema]
define
entity organization,
owns username,
owns status,
plays friendship:friend;
```

Let’s commit and move on!

Finally, yet another fundamental and powerful feature of TypeDB’s type system is **subtyping**. Analogous to modern programming language features, this gives us the ability to organize our types hierarchically. The next example illustrates how this works.

*   Studio
    
*   Console
    

Let’s define two types that specialize our earlier `organization` type: namely, we’ll define `company` and `university` as special cases, i.e., subtypes of `organization`. The keyword to define subtypings is `sub`. Run the following query:

```typeql
define
entity company sub organization;
entity university sub organization;
```

Note that we haven’t defined any interfaces for companies and universities; indeed, all interfaces of the supertype `organization` are automatically **inherited**! That doesn’t stop from defining new interfaces for our subtypes, of course:

```typeql
define
attribute student-count, value integer;
relation enrolment, relates university, relates student;
university owns student-count, plays enrolment:university;
user plays enrolment:student;
```

Of course, you would be able to give the new subtypes additional interfaces that are not inherited from the supertype as well!

Let’s define two types that specialize our earlier `organization` type: namely, we’ll define `company` and `university` as special cases, i.e., subtypes of `organization`. The keyword to define subtypings is `sub`. Run the following query:

```typeql
#!test[schema]
define
entity company sub organization;
entity university sub organization;
```

Note that we haven’t defined any interfaces for companies and universities; indeed, all interfaces of the supertype `organization` are automatically **inherited**! That doesn’t stop from defining new interfaces for our subtypes, of course:

```typeql
#!test[schema]
define
attribute student-count, value integer;
relation enrolment, relates university, relates student;
university owns student-count, plays enrolment:university;
user plays enrolment:student;
```

Of course, you would be able to give the new subtypes additional interfaces that are not inherited from the supertype as well!

Don’t forget to commit the transaction by typing `commit` and pressing kbd\[Enter\].

TypeDB’s type system re-thinks data models from first principles: it modularizes schemas into their "atomic" components. For example, you can add or remove roles and ownerships at any point in time, or edit specific annotations. This makes it easy to migrate and combine data, and programmatically re-structure your database if necessary. There is much more to explore. You can check out the [TypeQL Concepts](../../../core-concepts/typeql/index.md) section for specific details.

Here’s your entire schema so you can see it in one go:

```typeql
#!test[schema]
define
attribute username,
 value string;
attribute start-date,
 value datetime;
attribute status,
 value string;
attribute student-count,
 value integer;
entity user,
  owns status @card(0..),
  owns username @key,
  plays enrolment:student,
  plays friendship:friend;
entity organization,
  owns status,
  owns username,
  plays friendship:friend;
entity company,
  sub organization;
entity university,
  sub organization,
  owns student-count,
  plays enrolment:university;
relation friendship,
  relates friend @card(2..2),
  owns start-date @card(0..1);
relation enrolment,
  relates student,
  relates university;
```

Congratulations! You’ve set up a fully-fledged database with a real schema!

In the next section, you’ll start writing queries against it to insert and retrieve data.

[Setup](../setup/index.md) [Create data](../data/index.md)

[Edit on GitHub](https://github.com/typedb/typedb-docs/edit/3.x-development/learn-typedb/modules/ROOT/pages/quickstart/schema.adoc) Edit this page on GitHub.