# D2 Basics Tutorial

### What is D2? Is it that robot from star wars?

**No! D2** is a diagram scripting language that turns text to diagrams. It stands for **Declarative Diagramming**. Declarative, as in, you describe what you want diagrammed, it generates an image (SVG)

For example, you provide this input on the right, and you get back the output on the left.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675260186740/83c65697-5929-4e8e-8175-77fff0723c8f.gif align="center")

### Getting Started

To install D2 on you local machine you can use a script or an installer

* Use script to install D2
    

```plaintext
# With --dry-run the install script will print the commands it will use
# to install without actually installing so you know what it's going to do.
curl -fsSL https://d2lang.com/install.sh | sh -s -- --dry-run
# If things look good, install for real.
curl -fsSL https://d2lang.com/install.sh | sh -s --
```

* Install from source using go
    
    ```plaintext
    go install oss.terrastruct.com/d2
    ```
    
* For windows installation you can check out this link [https://github.com/terrastruct/d2/releases](https://github.com/terrastruct/d2/releases) for releases and installers
    
* To check if D2 is installed correctly run command d2 in your terminal you should see something like this
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675260630411/1e12b6e1-17c5-41a0-8da6-a5a911b6a89e.png align="center")

### Hello World D2

Let's start with the basics of D2 i.e a hello world example

1. Create a file named hello.d2 in any editor of your choice and paste this text in that file
    

```plaintext
x -> y: hello world
```

1. Navigate to that file in your terminal and run
    

```plaintext
d2 -w hello.d2 out.svg
```

will start a web server and serve an SVG file like this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675260847804/0e91f967-83d8-4fea-ad39-42faf0479a31.png align="center")

# Shapes

What are shapes? basically in every diagram that we need we need some shapes to be linked. For example in the hello world example we needed 2 boxes "x" and "y" to be linked to each other, these boxes are called as shapes in D2

Naming of shapes can be pretty simple below are a few examples of shapes

```plaintext
imAShape
im_a_shape
im a shape
i'm a shape
# notice that one-hyphen is not a connection
# whereas, `a--shape` would be a connection
a-shape
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675261076495/6f04b8c6-ad54-4dd5-8989-5ed61bad3c78.png align="center")

Avoid using double hyphen "--" while naming as that will create a connection instead.

You can also use semicolons to define multiple shapes on the same line for example this code

```plaintext
SQLite; Cassandra
```

Will generate

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675261258953/44d81ca5-55be-4654-9eaa-a6bc82aa4b37.png align="center")

By default, a shape's label is the same as the shape's key. But if you want it to be different, assign a new label like

```plaintext
pg: PostgreSQL
```

will generate a shape pg with label "PostgreSQL"

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675261338213/a7e41a86-e0e4-4019-948d-38623996755d.png align="center")

By default, a shape's type is `rectangle`. To specify otherwise, provide the field `shape`

```plaintext
pg: PostgreSQL
pg.shape: cloud
```

Will generate a cloud shape instead

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675261416713/2727f2a6-9554-46e2-a103-3233a2fee098.png align="center")

Here i have listed all the available shapes and how they look in the below image

```plaintext
pg1: cloud
pg1.shape: cloud

pg2: rectangle
pg2.shape: rectangle

pg3: square
pg3.shape: square

pg4: page
pg4.shape: page

pg5: parallelogram
pg5.shape: parallelogram

pg6: document
pg6.shape: document

pg7: cylinder
pg7:shape: cylinder

pg8: queue
pg8.shape: queue

pg9: package
pg9.shape: package

pg10: step
pg10.shape: step

pg11: callout
pg11.shape: callout

pg12: stored_data
pg12.shape: stored_data

pg13: person
pg13.shape: person

pg14: diamond
pg14.shape: diamond

pg15: oval
pg15.shape: oval

pg17: circle
pg17.shape: circle

pg18: hexagon
pg18.shape: hexagon

pg19: cloud
pg19.shape: cloud

pg19: text
pg19.shape: text

pg20: code
pg20.shape: code

pg21: class
pg21.shape: class

pg22: sql_table
pg22.shape: sql_table

pg23: image
pg23.shape: image
pg23.icon: https://icons.terrastruct.com/infra/019-network.svg

pg24: sequence_diagram
pg24.shape: sequence_diagram
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675262108924/262c3d82-aadd-472b-93a4-0a682dbd500d.svg align="center")

# Connections

Hyphens/arrows in between shapes define a connection. For example

```plaintext
Write Replica Canada <-> Write Replica Australia

Read Replica <- Master
Write Replica -> Master

Read Replica 1 -- Read Replica 2
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675263845434/ff809eb4-312d-4044-957f-11fca26642ae.png align="center")

There are 4 valid ways to define a connection:

* `-- Creates a connection between shapes`
    
* `-> Creates a uni directional connection example a -> b`
    
* `<- Creates a uni directional connection example b -> a`
    
* `<-> Creates a bi directional connection`
    

### Connection labels

Use colon to give a label to a connection for example

```plaintext
Read Replica 1 -- Read Replica 2: Kept in sync
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675264014298/78c8fa62-11f6-4f3d-8391-ce2eefb4af16.png align="center")

### Connections must reference a shape's key, not its label.

```plaintext
#shape be with label Backend
be: Backend 

#shape fe with label Frontend
fe: Frontend 

# This would create new shapes
Backend -> Frontend

# This would define a connection over existing shapes
be -> fe
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675264224895/2343a23b-b7e2-46d8-8e90-a23c70fe135c.png align="center")

## Repeated connections[​](https://d2lang.com/tour/connections#repeated-connections)

Repeated connections do not override existing connections. They declare new ones.

```plaintext
# Connection from Database to S3 with label "backup"
Database -> S3: backup 
# Connection from Database to S3
Database -> S3
# Connection from Database to S3 with label "backup"
Database -> S3: backup # Will create another connection
```

Will generate something like this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675264443662/a060b0f0-c1bf-4649-9fa4-4846ba48bd2b.png align="center")

## Connection chaining[​](https://d2lang.com/tour/connections#connection-chaining)

For readability, it may look more natural to define multiple connection in a single line.

```plaintext
# The label applies to each connection in the chain.
Instance1 -> EC2 <- Instance2: Hosted By
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675269216375/252bb086-53b6-4b92-bc48-8264c7509a1b.png align="center")

## Connection Cycles

We can also do chained connection cycles

```plaintext
Stage One -> Stage Two -> Stage Three -> Stage Four
Stage Four -> Stage One: repeat
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675269341580/c6d7e357-72a0-47b8-b51d-718ffa488892.png align="center")

## Arrowheads

To override the default arrowhead shape or give a label next to arrowheads, define a special shape on connections named `source-arrowhead` and/or `target-arrowhead`.

```plaintext
# Defined a shape with label
a: The best way to avoid responsibility is to say, "I've got responsibilities"
# Defined b shape with label
b: Whether weary or unweary, O man, do not rest
# Defined c shape with label
c: I still maintain the point that designing a monolithic kernel in 1991 is a

# Defined uni connection between a and b shape with label and custom connection arrowhead
a -> b: To err is human, to moo bovine {
  source-arrowhead: 1
  target-arrowhead: * {
    shape: diamond
  }
}

# Defined bi connection between b and c shape with label and custom connection arrowhead
b <-> c: "Reality is just a crutch for people who can't handle science fiction" {
  source-arrowhead.label: 1
  target-arrowhead: * {
    shape: diamond
    style.filled: true
  }
}

# Defined d shape with label
d: A black cat crossing your path signifies that the animal is going somewhere

d -> a -> c
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675269543766/5ffa61e6-cb02-42e6-af97-5d86747bc2cf.png align="center")

### *ARROWHEAD OPTIONS*

* `triangle` (default)
    
* `arrow` (like triangle but pointier)
    
* `diamond`
    
    * Can be further styled as `style.filled: true`.
        
* `circle`
    
    * Can be further styled as `style.filled: true`.
        
* `cf-one`, `cf-one-required` (cf stands for crows foot)
    
* `cf-many`, `cf-many-required`
    

Sample Example

```plaintext
a -> b: triangle {
  source-arrowhead: 1
  target-arrowhead: * {
    shape: triangle
  }
}

c -> d: arrow {
  source-arrowhead: 1
  target-arrowhead: * {
    shape: arrow
  }
}

e -> f: circle {
  source-arrowhead: 1
  target-arrowhead: * {
    shape: circle
  }
}
g -> h: cf-one {
  source-arrowhead: 1
  target-arrowhead: * {
    shape: cf-one
  }
}
i -> j: cf-one-required {
  source-arrowhead: 1
  target-arrowhead: * {
    shape: cf-one-required
  }
}
k -> l: cf-many {
  source-arrowhead: 1
  target-arrowhead: * {
    shape: cf-many
  }
}

m -> n: cf-many-required {
  source-arrowhead: 1
  target-arrowhead: * {
    shape: cf-many-required
  }
}
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675270025657/8133cde6-a579-49cc-a4a2-a4460b54c2a9.png align="center")

# Containers

Containers are shapes that can contain other shapes within them for example

```plaintext
server
# Declares a shape inside of another shape
server.process

# Can declare the container and child in same line
parent.child

# Since connections can also declare keys, this works too
apartment.Bedroom.Bathroom -> office.Spareroom.Bathroom: Portal
```

The above code will generate output like this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675270226792/47fb23c9-50bc-4001-bd76-29bb9b21f371.png align="center")

## Nested syntax[​](https://d2lang.com/tour/containers#nested-syntax)

You can avoid repeating containers by creating nested maps.

```plaintext
clouds: {
  aws: {
    load_balancer -> api
    api -> db
  }
  gcloud: {
    auth -> db
  }

  gcloud -> aws
}
```

The above code will generate an output like

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675270301475/424f6c3e-b42f-40a0-a94b-be25651daf7e.png align="center")

## Container labels[​](https://d2lang.com/tour/containers#container-labels)

There are two ways define container labels.

### 1\. Shorthand container labels[​](https://d2lang.com/tour/containers#1-shorthand-container-labels)

```plaintext
gcloud: Google Cloud {
...
}
```

### 2\. Reserved keyword `label`[​](https://d2lang.com/tour/containers#2-reserved-keyword-label)

```plaintext
gcloud: {
   label: Google Cloud
   ...
}
```

Example

```plaintext
clouds: {
  aws: AWS {
    load_balancer -> api
    api -> db
  }
  gcloud: Google Cloud {
    auth -> db
  }

  gcloud -> aws
}

users -> clouds.aws.load_balancer
users -> clouds.gcloud.auth

ci.deploys -> clouds
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675270374461/bfb55a4e-78c1-46b8-8ae5-946a5b826741.svg align="center")

## Reference parent[​](https://d2lang.com/tour/containers#reference-parent)

Sometimes you want to reference something outside of the container from within. The underscore (`_`) refers to parent.

```plaintext
christmas: {
  presents
}
birthdays: {
  presents
  _.christmas.presents -> presents: regift
  _.christmas.style.fill: "#ACE1AF"
}
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1675270699107/5200c1be-1772-42a2-ae18-fea324b2400b.png align="center")
