---
title: Collections
description: Collections hold your JSON records. Create them, choose who can see them, and publish read-only data without an API key.
group: Working with data
order: 1
keywords: [collections, json collection, database table alternative, public json api, visibility]
---

# Collections

A collection is one box of similar things. If you are coming from SQL, it is roughly a
table; if you are coming from Firebase, it is roughly a collection. One per kind of
thing: `todos`, `bookmarks`, `signups`, `posts`.

Every collection has a **name** (what you see) and a **slug** (what you type in URLs).
Create one from the dashboard with **New collection**, or from the API with
`collections:create`.

You do not have to decide on fields up front. A new collection accepts any JSON. Add a
[schema](/docs/schemas) later, once you know what the data looks like.

## Create one from the API

```bash
curl -s -X POST "$BAAS_URL/workspaces/$BAAS_WS/collections" \
  -H "Authorization: Bearer $BAAS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Todos","slug":"todos","visibility":"private"}'
```

## Who can see a collection

Visibility is a collection setting. There are four values:

| Visibility    | Who can read it                                                            |
| ------------- | -------------------------------------------------------------------------- |
| `private`     | You, workspace owners and admins, and anyone you invite to this collection |
| `workspace`   | Everyone in the workspace, with whatever role they have                    |
| `public_read` | Anyone on the internet, read-only, with no key                             |
| `unlisted`    | Anyone with the secret link, read-only, with no key                        |

Writing always needs a key or a signed-in person. Public and unlisted only ever open up
reading.

## Public and unlisted collections

This is the one case where you do **not** need an API key, which makes it the right
choice for data a browser should fetch directly — a blog index, a changelog, a public
leaderboard.

Set the collection's visibility to **Public read** in its settings, then anyone can call:

```bash
curl -s "https://www.wrongnotebook.com/v1/public/collections/COLLECTION_ID/records"
```

```js
// Safe in browser JavaScript: no key involved.
const res = await fetch(
  'https://www.wrongnotebook.com/v1/public/collections/COLLECTION_ID/records?limit=20',
);
const { data } = await res.json();
```

Public endpoints use the collection's **UUID**, not its slug, and they accept the same
[filters, sorting and paging](/docs/queries) as the private API.

**Unlisted** works the same way but requires a token in the URL
(`?token=…`), so only people with the link can read it. Rotate that token from the
collection's settings if the link spreads further than you wanted.

> Anything in a public collection is public. Do not put email addresses, private notes
> or anything you would not post on a web page into one.

## Import and export

Your data is not locked in.

```bash
# Export (json, ndjson or csv)
curl -s "$BAAS_URL/workspaces/$BAAS_WS/collections/todos/export?format=json" \
  -H "Authorization: Bearer $BAAS_KEY" -o todos.json

# Import, all-or-nothing by default
curl -s -X POST "$BAAS_URL/workspaces/$BAAS_WS/collections/todos/import" \
  -H "Authorization: Bearer $BAAS_KEY" -H "Content-Type: application/json" \
  -d '{"records":[{"data":{"title":"From a file","done":false}}]}'
```

Useful flags on import:

- `"dryRun": true` — check the file without writing anything, and get a report.
- `"mode": "partial"` — write the valid records and report the rest. The default,
  `atomic`, writes everything or nothing, so a bad row cannot leave you half-imported.

NDJSON is accepted too, with `Content-Type: application/x-ndjson` and one record per
line. Exported NDJSON can be imported straight back.

## Duplicate, archive and delete

- **Duplicate** copies a collection, with or without its records. Handy for making a
  staging copy before a risky change.
- **Archive** moves it to the trash. Nothing is lost and you can restore it.
- **Delete permanently** is separate, asks you to type the slug to confirm, and cannot be
  undone.

Deleting a collection for good also removes its records, revisions, schema versions and
files. The audit log keeps the record that it happened.

## Limits

|                           |                |
| ------------------------- | -------------- |
| Collections per workspace | 200            |
| Records per import        | 10,000 (10 MB) |

## Next steps

- [Records](/docs/records) — writing and reading the contents.
- [Schemas](/docs/schemas) — enforcing a shape once you know it.
