Skip to content

Concourse Command Language (CCL)#

The Concourse Command Language (CCL) is the language for interacting with Concourse. CCL is built around commands — human-readable statements that read, write, query, and manage data. All CCL keywords are case-insensitive.

1
select name, age from 1 where active = true order by name

Commands can include conditions to filter records, timestamps for time travel, ordering to sort results, and pagination to limit output.

Multi-Statement Input#

Separate multiple commands with semicolons:

1
add name as "Jeff" in 1; set age as 30 in 1; select from 1

Leading, trailing, and consecutive semicolons are tolerated.


Commands#

Every CCL command begins with a verb that identifies the operation, followed by parameters specific to that operation. The general pattern is:

1
2
verb [keys] [preposition] [records] [where condition]
    [at timestamp] [order by ...] [skip N] [limit N]

Not all clauses apply to every command. The sections below document each command’s specific syntax.

Read Commands#

SELECT#

Return all values for key(s) in record(s) or matching records.

1
2
3
4
5
6
7
8
9
select name from 1
select [name, age] from 1
select 1
select 1, 2, 3
select name where age > 30
select where age > 30
select name from 1 at "yesterday"
select name from 1 as of "2025-01-01"
select where age > 30 order by name limit 10

GET#

Return the most recent value for key(s). Same syntax as select.

1
2
3
4
5
6
get name from 1
get [name, age] from [1, 2, 3]
get name where age > 30
get where age > 30
get from 1
get 1

FIND#

Return the IDs of records matching a condition.

1
2
3
4
5
find age > 30
find name = "Jeff" and active = true
find age > 30 order by name
find age > 30 skip 20 limit 10
find name = "Jeff" at "yesterday"

Full-text search for a query string within a key.

1
2
search name for "Jeff"
search description for "distributed database"

BROWSE#

Return an inverted index of all values for a key.

1
2
3
browse name
browse [name, age]
browse name at "yesterday"

Traverse links and return data from linked records.

1
2
3
4
navigate friends.name from 1
navigate [friends.name, age] from [1, 2]
navigate friends.name where age > 30
navigate friends.name from 1 at "yesterday"

DESCRIBE#

List the keys that have values in a record.

1
2
3
4
describe
describe 1
describe [1, 2, 3]
describe 1 at "yesterday"

VERIFY#

Check whether a specific key-value pair exists.

1
2
verify name as "Jeff" in 1
verify name as "Jeff" in 1 at "yesterday"

HOLDS#

Check whether records contain any data.

1
2
holds 1
holds [1, 2, 3]

INVENTORY#

Return the IDs of all records in the database.

1
inventory

JSONIFY#

Export records as JSON. The $id$ key is included by default; use without $id$ to exclude it.

1
2
3
4
jsonify 1
jsonify [1, 2, 3]
jsonify 1 without $id$
jsonify 1 at "yesterday"

Write Commands#

ADD#

Append a value to a key. If no record is specified, a new record is created.

1
2
3
add name as "Jeff Nelson"
add name as "Jeff Nelson" in 1
add name as "Jeff Nelson" to [1, 2, 3]

SET#

Atomically replace all values for a key with a single new value.

1
2
set email as "jeff@cinchapi.com" in 1
set status as "active" within [1, 2, 3]

REMOVE#

Remove a specific value from a key.

1
2
remove tag as "beta" from 1
remove tag as "beta" from [1, 2, 3]

CLEAR#

Remove all values for key(s) in record(s), or clear entire records.

1
2
3
4
clear 1
clear [1, 2, 3]
clear name from 1
clear [name, age] from [1, 2, 3]

INSERT#

Insert a JSON document as a new record, or into existing record(s).

1
2
3
insert '{"name": "Jeff", "age": 30}'
insert '{"status": "active"}' in 1
insert '{"role": "admin"}' into [1, 2, 3]

VERIFY_AND_SWAP#

Atomic compare-and-swap: replace a value only if the expected value is currently stored.

1
2
verifyAndSwap balance as 100 in 1 with 90
verify_and_swap status as "pending" in 42 with "active"

VERIFY_OR_SET#

Ensure a field contains exactly one specific value, making changes only if necessary.

1
2
verifyOrSet status as "active" in 1
verify_or_set name as "Jeff" in 1

RECONCILE#

Synchronize a field to contain exactly the specified values.

1
reconcile tags in 1 with [database, nosql, java]

FIND_OR_ADD#

Find the unique record where a key equals a value, or add a new one if none exists.

1
2
findOrAdd email as "jeff@example.com"
find_or_add name as "Jeff"

FIND_OR_INSERT#

Find the unique record matching a condition, or insert JSON if none exists.

1
2
findOrInsert age > 30 '{"name": "Jeff", "age": 35}'
find_or_insert name = "Jeff" '{"name": "Jeff"}'

CONSOLIDATE#

Merge two or more records into one.

1
2
consolidate 1 2
consolidate 1 [2, 3, 4]

Create a directed link from a source record to a destination.

1
2
link friends from 1 to 2
link friends from 1 to [2, 3, 4]

Remove a link.

1
unlink friends from 1 to 2

Historical Commands#

AUDIT#

View the complete revision history for a record or field.

1
2
3
4
audit 1
audit name in 1
audit 1 from "last month" to "today"
audit name in 1 from "2025-01-01" to "2025-06-01"

CHRONICLE#

View a time series of a field’s values after every change.

1
2
chronicle name in 1
chronicle name in 1 from "2025-01-01" to "2025-06-01"

DIFF#

Compute the net changes between two points in time.

1
2
3
4
diff 1 from "yesterday"
diff 1 from "yesterday" to "today"
diff name in 1 from "yesterday" to "today"
diff name from "last week" to "today"

REVERT#

Restore key(s) in record(s) to their state at a previous timestamp.

1
2
3
revert name in 1 at "yesterday"
revert name in [1, 2, 3] at "2025-01-01"
revert [name, age] in 1 at "last week"

TRACE#

Find all incoming links to a record.

1
2
3
trace 1
trace [1, 2, 3]
trace 1 at "yesterday"

Aggregation Commands#

CALCULATE#

Perform aggregate calculations over values.

1
2
3
4
5
6
calculate sum age
calculate avg score in 1
calculate count name within [1, 2, 3]
calculate sum salary where department = "Engineering"
calculate avg score where score > 50 at "yesterday"
calculate count $id$ where active = true

Supported functions: avg (or average), sum, count, min, max.

Transaction Commands#

STAGE#

Begin a transaction. Subsequent commands are buffered until committed or aborted.

1
stage

COMMIT#

Commit the current transaction.

1
commit

ABORT#

Abort the current transaction and discard all buffered changes.

1
abort

Utility Commands#

PING#

Server health check.

1
ping

Conditions#

A condition is a boolean expression used within commands to filter which records are affected. Conditions appear after the where keyword in commands like find, select, get, navigate, and calculate.

1
2
3
find age > 30 and active = true
select name where department = "Engineering"
calculate avg salary where role = "Engineer"

Relational Expressions#

The basic unit of a condition is a relational expression:

1
key operator value

Examples:

1
2
3
4
name = "Jeff Nelson"
age > 30
score >= 90
email != "admin@example.com"

Operators#

Comparison Operators#

Operator Aliases Description
= ==, eq, equals Equals
!= ne, not_equals Not equals
> gt, greater_than Greater than
>= gte, greater_than_or_equals Greater than or equal
< lt, less_than Less than
<= lte, less_than_or_equals Less than or equal

Range Operator#

Operator Aliases Description
>< bw, between Between two values (inclusive)

The between operator requires two values:

1
2
age bw 18 65
score between 80 100

Pattern Operators#

Operator Aliases Description
regex Regular expression match
nregex not_regex Negated regex match
like SQL-style pattern match
nlike not_like Negated pattern match
1
2
3
name regex "[A-Z][a-z]+"
email like "%@example.com"
name not_like "%test%"

Search Operators#

Operator Aliases Description
~ contains, search_match Full-text search match
!~ not_contains, search_exclude Negated full-text search
1
2
bio contains "distributed systems"
name !~ "admin"

These operators perform full-text search against the search index rather than exact string comparison. See Search.

Operator Aliases Description
-> lnk2, lnks2, links_to Links to a record
1
2
employer -> 100
friends lnk2 42

See Graph for details.

Logical Connectives#

Combine expressions with and and or:

Connective Aliases Description
and &&, & Both must be true
or \|\| Either must be true
1
2
age > 30 and department = "Engineering"
status = "active" or status = "pending"

Parenthetical Grouping#

Use parentheses to override default precedence:

1
2
(department = "Engineering" or department = "Design")
    and active = true

Operator Precedence#

  1. Parentheses ()
  2. Relational operators=, !=, >, etc.
  3. ANDand, &&, &
  4. ORor, ||

AND binds more tightly than OR:

1
2
3
a = 1 or b = 2 and c = 3
-- equivalent to:
a = 1 or (b = 2 and c = 3)

Temporal Conditions#

Append a timestamp to evaluate a condition against historical data:

1
2
3
name = "Jeff" at "yesterday"
age > 30 on "2025-01-01"
score >= 90 during "last week"

Keys#

Simple Keys#

Alphanumeric identifiers:

1
2
3
4
name
age
favorite_color
$id$

Dot-separated paths that traverse links between records:

1
2
3
employer.name
friends.age
employer.address.city

Navigation keys work anywhere a simple key is accepted, including in conditions:

1
2
3
find employer.name = "Cinchapi"
select friends.age from 1
navigate employer.ceo.name from 1

See Graph for details.

Function Keys#

A key piped to an aggregation function using |:

1
2
3
score | avg > 80
age | sum > 1000
items | count > 5

Values#

Strings#

Syntax Example
Double-quoted "Jeff Nelson"
Single-quoted 'Jeff Nelson'
Backtick-quoted `Jeff Nelson`
Unquoted Jeff (single word, no keyword conflict)

Unquoted multi-word values are supported when unambiguous:

1
name = Jeff Nelson

Numbers#

1
2
3
4
42                 -- integer
-7                 -- signed integer
3.14               -- decimal
-2.5               -- signed decimal

Record Identifiers#

Positive integers reference records by ID:

1
2
select name from 1
get name from 42

Collections#

Multiple items use brackets or commas:

1
2
3
select name from [1, 2, 3]
select name from 1, 2, 3
clear [name, age] from 1

The $id$ Key#

The special $id$ key refers to a record’s unique identifier:

1
2
calculate count $id$ where active = true
jsonify 1 without $id$

Variable References#

Values prefixed with $ are resolved from a provided data context:

1
2
age bw $minAge $maxAge
name = $targetName

Escape Sequences#

Sequence Result
\" Literal " inside double-quoted strings
\' Literal ' inside single-quoted strings
\$ Literal $ (prevents variable resolution)
\@ Literal @

Timestamps#

Timestamps enable time travel — querying and reading data as it existed at a previous point in time.

Keywords#

Keyword Context
at All contexts
on All contexts
during All contexts
in Conditions
as of Read commands only

Values#

Natural language:

1
2
3
4
5
"yesterday"
"3 days ago"
"last week"
"last Tuesday"
"January 1, 2025"

Date strings:

1
2
"2025-01-15"
"2025-01-15 10:30:00"

Microsecond epoch: A numeric value representing microseconds since the Unix epoch.

In Commands#

1
2
3
4
select name from 1 at "yesterday"
get name from 1 as of "2025-01-01"
find age > 30 at "last month"
describe 1 at "yesterday"

In Conditions#

1
2
name = "Jeff" at "yesterday"
age > 30 on "2025-01-01"

Time Ranges#

Some commands support ranges with from and to:

1
2
3
audit 1 from "last month" to "today"
chronicle name in 1 from "2025-01-01" to "2025-06-01"
diff 1 from "yesterday" to "today"

Ordering#

The order by clause sorts results returned by read commands.

Direction#

Syntax Meaning
asc (default) Ascending (word suffix)
desc Descending (word suffix)
< Ascending (symbolic prefix)
> Descending (symbolic prefix)

Examples#

1
2
3
4
5
order by name
order by name asc
order by age desc
order by <name
order by >age

Multi-Key Ordering#

1
2
order by department asc, name asc
order by >age, <name

Temporal Ordering#

Sort by the value at a specific timestamp:

1
2
order by name at "yesterday"
order by score desc at "2025-01-01"

Pagination#

Control which subset of results to return.

Keyword Alias Description
skip offset Number of results to skip (0-indexed)
limit Maximum number of results
1
2
3
skip 20 limit 10
limit 10 skip 20
offset 0 limit 50

The parts can appear in either order.

Combined with Ordering#

1
2
find age > 30 order by name asc skip 20 limit 10
select name where active = true order by name limit 25

Functions#

Functions compute aggregate values. They can appear within conditions or as standalone calculate commands.

Supported Functions#

avg (or average), sum, count, min, max

Pipe Syntax (Implicit Key)#

1
2
3
score | avg
score | avg > 80
age | sum > 1000

Call Syntax (Explicit)#

Across all records:

1
2
avg(score)
age > avg(age)

With timestamp:

1
age > avg(age, at "yesterday")

Over specific records:

1
2
3
avg(score, 1, 2, 3)
sum(score, [1, 2, 3])
sum(score, [1, 2, 3], at "yesterday")

Over records matching a condition:

1
2
avg(age, department = "Engineering")
sum(score, status = "active", at "last week")

Prepositions#

CCL accepts semantically appropriate prepositions before record references. Prepositions within each group are interchangeable.

Commands Accepted Prepositions
ADD, INSERT in, to, within, into
SET in, within
SELECT, GET, NAVIGATE, CALCULATE from, in, within
REMOVE, CLEAR from, in, within
VERIFY, CHRONICLE, DIFF, AUDIT, REVERT, RECONCILE in, within
LINK, UNLINK fromto

Quick Reference#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
-- Read data
select name, age from 1
get name from 1 at "yesterday"
find age > 30 and active = true
find age > 30 order by name skip 20 limit 10
search name for "Jeff"
browse name
navigate employer.name from 1
describe 1
holds 1
inventory

-- Write data
add name as "Jeff" in 1
set status as "active" in 1
remove tag as "beta" from 1
clear name from 1
insert '{"name": "Jeff", "age": 30}'
link friends from 1 to 2

-- Atomic operations
verifyAndSwap balance as 100 in 1 with 90
verifyOrSet status as "active" in 1
findOrAdd email as "jeff@example.com"
reconcile tags in 1 with [v1, stable, release]
consolidate 1 [2, 3]

-- Time travel
audit 1
chronicle name in 1
diff 1 from "yesterday" to "today"
revert name in 1 at "last week"
trace 1

-- Aggregation
calculate avg salary where department = "Engineering"
calculate count $id$ where active = true

-- Transactions
stage
commit
abort