# Check
URL: https://permix.letstri.dev/docs/guide/check

Learn how to check permissions in your application



## Overview [#overview]

Permix provides the `check` method for verifying permissions. It returns a boolean indicating whether the action is allowed.

## Dot paths [#dot-paths]

Check a single action using a dot-separated path:

```ts
permix.check('post.create') // returns true/false
```

## Multiple actions [#multiple-actions]

Combine multiple checks with a callback. All conditions must be truthy:

```ts
// Check if both create and read are allowed
permix.check((c) => c('post.create') && c('post.read'))
```

## All [#all]

Use the `~all` special token to verify if all possible actions in a subtree are permitted:

```ts
// Check if all post actions are allowed
permix.check('post.~all')

// Check if all actions in the entire permission tree are allowed
permix.check('~all')
```

## Any [#any]

Use the `~any` special token to verify if any action in a subtree is permitted:

```ts
// Check if any post action is allowed
permix.check('post.~any')

// Check if any action in the entire permission tree is allowed
permix.check('~any')
```

## Waiting for setup [#waiting-for-setup]

When permissions might be set up asynchronously, wait for the instance to be ready before checking:

```ts
setTimeout(() => {
  permix.setup({
    post: { create: true },
  })
}, 1000)

await permix.isReadyAsync()
permix.check('post.create')
```

<Callout>
  In most cases you should use `check` directly. Use `isReadyAsync()` when you
  need to ensure permissions are ready before checking, for example in route
  middleware.
</Callout>

## Data-Based [#data-based]

You can define permissions that depend on the data being accessed:

```ts
permix.setup({
  post: {
    // Only allow updates if user is the author
    update: (post) => post.authorId === currentUserId,
    // Static permission
    read: true,
  },
})

// Check with data
const post = { id: '1', authorId: 'user1' }

permix.check('post.update', post) // true if currentUserId === 'user1'
```

<Callout type="warn">
  You can still check permissions without providing the data, but dynamic rules
  that require entity data will return `false` in that case.
</Callout>

## Type Safety [#type-safety]

Permix provides full type safety for your permissions:

```ts twoslash
import { createPermix } from 'permix'

const permix = createPermix<{
  post: ['create', 'update']
}>()

// @errors: 2345
permix.check('post.invalid-action')

permix.check('invalid-entity.create')
```

Invalid paths cause a TypeScript error at compile time. At runtime, checking an undefined path throws `PermixRuleNotDefinedError`.

## Errors [#errors]

Permix throws typed errors from `permix` when checks cannot run safely:

| Error                       | When                                                                                                                                                                         |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PermixNotReadyError`       | `check()` or `dehydrate()` runs before any rules exist (no `setup()` and no initial rules).                                                                                  |
| `PermixRuleNotDefinedError` | `check()` targets a path that is not present in the current rules object, or is deeper than the rules tree (for example rules `{ post: true }` with `check('post.create')`). |

After `hydrate()`, boolean rules are available immediately — `check()` works even while `isReady()` is still `false`. Function-based rules still need a follow-up `setup()` on the client. See [Hydration](/docs/guide/hydration) and [Ready State](/docs/guide/ready).

`PermixNotFoundError` is thrown by server integrations when middleware was not registered on the request — see [Server](/docs/integrations/server) and [Node.js](/docs/integrations/node).
