---
source_url: https://www.pubnub.com/docs/general/data-sync/projections
title: Projections in DataSync
updated_at: 2026-09-08T16:52:30.000Z
---

# Projections in DataSync

## Documentation index

To discover more PubNub resources:

1. Fetch [PubNub's llms.txt](https://www.pubnub.com/llms-full.txt) for a list of available pages in Markdown format.
2. Identify relevant URLs from that index.
3. Fetch the target pages.

Do not assume a path exists, always check the index first.

A projection is a named view over an object's fields. A client's Access Manager token determines which view it gets when it reads or writes that object. Projections aren't a separate permission system. They live inside the same Access Manager tokens that already authorize the rest of PubNub.

In [Bob's marketplace](https://www.pubnub.com/docs/general/data-sync/overview.md#running-example-bobs-live-marketplace), Alice's user profile has fields everyone in the sale channel may see, like `display_name` and `avatar_url`, and fields only support staff should see, like `email` and `phone`. Projections let you draw that line at the field level.

## How projections work

A projection is a named tag declared on a property definition, at the class level. A single field can belong to several projections.

The projection names you can grant on an object are the ones its class declares, so read them off the class definition with [Get entity class by ID](https://www.pubnub.com/docs/admin-api/get-entity-class-by-id.md) or [Get relationship class by name and version](https://www.pubnub.com/docs/admin-api/get-relationship-class-by-name-and-version.md), and set them with [Create a new entity class](https://www.pubnub.com/docs/admin-api/create-a-new-entity-class.md) or [Create a new relationship class](https://www.pubnub.com/docs/admin-api/create-a-new-relationship-class.md).

Each property carries its own list of projections, and that list defaults to the built-in `__default__` projection alone. So a field is broadly visible until you say otherwise, and you restrict a field by removing `__default__` from its list and tagging it with a named projection instead. That's what makes `email` and `phone` `admin`-only in the example below.

### Projection limits

A class can declare at most 3 distinct projection names across all of its properties. `__default__` counts toward that 3 whenever any property is tagged with it, which is the default, so in practice you have 2 custom names. Each name is at most 64 characters and must match `^[a-zA-Z0-9][a-zA-Z0-9_-]*$`. `__default__` is the only name allowed to start with `__`. Exceeding the limit or using an invalid name fails class creation or update with a `400`.

Projections overlap rather than partition. Nothing requires one projection to contain another, but a broadly visible field can carry several projection tags, which is how you make a restricted projection a superset that sees everything `__default__` sees plus the sensitive fields:

In the diagram, a token holding the `admin` projection for `user-alice` reads all four fields. A token that resolves to `__default__` reads only `display_name` and `avatar_url`, the two fields tagged `__default__`. A request authorized with a signature instead of a token isn't projection-filtered and reads all four.

###### Projections are declared on property definitions

Projection membership is set per property definition when you define a class. See [Schemas and validation](https://www.pubnub.com/docs/general/data-sync/schemas-and-validation.md).

## Projection resolution with a token

[Access Manager](https://www.pubnub.com/docs/general/security/access-control.md) tokens carry a `pn-projections` map inside their `meta` section. The map holds two nested maps, `res` for exact resource ids and `pat` for regular-expression patterns, and each value is the projection name granted for that resource.

Each object kind has its own key prefix. These prefixes are specific to the projections map, and differ from the resource types used for [permission grants](https://www.pubnub.com/docs/general/data-sync/access-control.md#permissions-and-resource-types):

* `datasync:users:` for users
* `datasync:entities:` for generic entities
* `datasync:channels:` for channels
* `datasync:relationships:` for relationships
* `datasync:memberships:` for memberships

```json
{
  "meta": {
    "pn-projections": {
      "res": {
        "datasync:users:user-alice": "admin"
      },
      "pat": {}
    }
  }
}
```

Resolution follows a fixed order: an exact match in `res` wins first, then a pattern match in `pat`, and if neither matches, the token falls back to `__default__`. A token with no `pn-projections` map also resolves to `__default__`.

Patterns are anchored regular expressions matched against the whole resource ID, so `user-.*` matches `user-alice` but `user` does not. If several patterns match, which one wins isn't defined, so avoid overlapping patterns. If a token resolves to a projection name that no property on the class declares, the request fails with a 403 error.

Refer to [Access control](https://www.pubnub.com/docs/general/data-sync/access-control.md) for the full information on tokens, grants, and resource types.

###### Tokens and resource types control access

Projections resolve from the same Access Manager tokens that grant access to DataSync resource types. See [Access control](https://www.pubnub.com/docs/general/data-sync/access-control.md).

## What projections enforce

Projections govern reads and writes, and the two kinds of projection aren't symmetric. `__default__` acts as a denylist that lets undeclared payload fields through, while a named projection acts as an allowlist that drops them:

* Reads under a named projection: the response contains only fields tagged with that projection. Anything else is removed, including payload fields that have no property definition. `status` is also removed unless the class declares a `/status` property tagged with that projection.
* Reads under `__default__`: the response removes declared fields not tagged `__default__`, and keeps payload fields that have no property definition.
* Writes: naming a field outside the token's resolved projection rejects the whole request with a `403`. DataSync never applies part of a rejected write, so the object is left exactly as it was. Under `__default__` you can also write payload fields that have no property definition. Under a named projection you can't.
* Replaces under a named projection only replace that projection's payload fields. Payload fields outside the projection keep their stored values rather than being wiped, so a restricted client can't destroy data it can't see.
* `status` is checked separately from payload fields. If the projection includes `/status`, omitting it from a replace clears it. If the projection excludes `/status`, changing it is rejected. Currently, omitting a stored non-null status is also treated as a change and returns a `403`.
* Partial updates are judged on the resulting document rather than on the paths they mention, so a patch that touches an out-of-projection path but leaves the value unchanged is allowed, while removing an out-of-projection field is rejected.

The `403` says only that the `auth` parameter was invalid. It doesn't name the field that was rejected.

## Projections and events

Projections scope events as well as API responses. Each change fans out to one event per projection declared on the class. The `__default__` variant is published to the object's own ID channel with the `__default__` view of the payload, and each named projection is published to a separate channel named `__<projection>__<id>` carrying that projection's view.

Continuing with Bob's marketplace: `email` and `phone` belong only to the `admin` projection, so an update to Alice publishes two events. The `user-alice` channel carries her `__default__` fields, with `email` and `phone` withheld. The `__admin__user-alice` channel carries the `admin` view, `email` and `phone` included.

If a class declares no properties at all, there is nothing to filter, so a single unfiltered event is published to the object's own ID channel.

:::warning Projection channels need channel grants
Publishing to `__<projection>__<id>` is an ordinary channel publish, and it isn't gated by the projection entries in a token. Use Access Manager channel grants to control who can subscribe to projection channels. Anyone who can subscribe there receives the restricted fields.
:::

In an SDK that ships [DataSync SDK entities](https://www.pubnub.com/docs/general/entities.md#datasync-sdk-entities), you select the projection channel with a `projection` subscription option rather than by naming the prefixed channel. It's the same channel either way, and the same channel grant applies.

## Designing projections

* Projections can overlap. A common pattern, as in the `admin` projection above, is to tag sensitive fields with only the restricted projection, while broadly visible fields carry both `__default__` and the restricted projection, so the restricted projection is a superset that sees everything `__default__` sees plus the sensitive fields.
* Remember the ceiling of 3 projections per class, and that `__default__` takes one of the three as soon as any property uses it. In practice that gives you 2 custom projections to model roles. Plan which fields go where before you reach the limit.
* Projections apply to events as well as the API, but each named projection gets its own event channel, `__<projection>__<id>`. Grant subscribe on those channels as carefully as you grant the projection itself, see [Projections and events](#projections-and-events) above.
* A token holding a named projection can't write payload fields you haven't declared on the class. If a client needs to store free-form data, leave it under `__default__`.

## Terms in this document

* **Access Manager** - A cryptographic, token-based permission administrator that allows you to regulate clients' access to PubNub resources, such as channels, channel groups, and user IDs.
* **Class** - A versioned type definition (name plus integer version) for entities or relationships in DataSync. Classes carry property definitions that declare which payload fields are validated, filterable, and scoped by projections.
* **Projection** - A named view over an object's payload fields in DataSync, controlling which fields a client can read and write based on its Access Manager token.

Last updated at: 2026-09-08T16:52:30.000Z
