The dashboard binds a small, fixed set of shortcuts. There is no remapping screen and no preference to disable them: the keys are hard coded, and each one is armed only where the action it triggers actually exists. This page lists all of them and states plainly where each is bound and where it does nothing.
The sidebar search button draws ⌘ K on macOS and Ctrl K everywhere else, and the narrow screen header search button carries the same label in its tooltip rather than on its face, but that label is only about which symbol to draw. Every combination below accepts either the meta key or the control key on every platform, so Ctrl K works on a Mac too.
Every shortcut
| Shortcut | Action | Where it applies |
|---|---|---|
⌘ K / Ctrl K | Open the command palette, or close it if it is already open | Every page inside the dashboard shell |
↑ ↓ | Move the highlight in the palette, wrapping at both ends | While the palette is open |
Home / End | Jump to the first or last result | While the palette is open |
↵ | Open the highlighted result | While the palette is open |
Esc | Close the palette | While the palette is open |
c | The page's primary create action | Products, a product, a project, an environment table view, Team, Keys, Roles, Webhooks |
p | Open Publish version | The environment table view only |
⌘ 1 to ⌘ 9 / Ctrl 1 to Ctrl 9 | Jump to the first nine entries of whichever switcher the sidebar is currently showing | Every page inside the dashboard shell. What it switches depends on how deep the URL is |
↵ while the pointer is hovering a sidebar link | Activate that link | The sidebar navigation lists, not the switcher button |
The dashboard shell is everything behind the sign-in wall. The sign-in page, the OTP page and the CLI authorization page sit outside it, so none of these shortcuts exist there.
Keys that belong to modals
Two more keys are bound by the modal machinery rather than by a page, which is why they are not in the table above. Esc closes the dialog, sheet or drawer on top, and the close button carries an esc chip for as long as that works: a modal that is mid request blocks the key and drops the chip, and the create key modal also blocks it while the new secret is still on screen. ↵ submits the modal you are in when focus is in a text field, file inputs excepted, and it is ignored while that modal is saving or while its form is not complete. The publish version modal is the only one that also takes a bare ↵ outside a field, with ⌘ ↵ or Ctrl ↵ for its note textarea. Both keys work on the sign-in and OTP forms too, which are otherwise outside all of this.
The command palette
⌘ K toggles: pressing it with the palette open closes it again. The listener sits on the window with no guard for the focused element, so it opens even while you are typing in a search box or a variable field.
Open it and the input reads Search products, projects, environments and pages..., which is the literal scope. Results arrive in four groups, always in this order, with empty groups hidden entirely:
| Group | Source | Order |
|---|---|---|
| Products | Every product in the current workspace you can access | Newest created first |
| Projects | Every project in the current workspace you can access, across all products | Newest created first |
| Environments | Environments of the 25 most recently created projects only | Newest created first, project by project |
| Pages | The sidebar navigation entries that resolve for the current URL | Fixed nav order |
Typing is debounced by 200 ms, then the query is sent to the API. Matching on products, projects and environments is a case insensitive substring match against the name and the slug, nothing else. An empty query is not a special case, it simply matches everything, so opening the palette and typing nothing lists the whole workspace. Page entries are filtered in the browser instead, against a keyword string built from the entry's title, its nav group and its URL.
The environment group fans out over the 25 most recently created projects only. If the workspace has more projects than that, environments in the older ones are never searched and never appear, with no indication that anything was left out. The projects and products groups are not capped this way. Environments are also matched on their own name and slug only, so typing a project's name surfaces the project but not its environments.
Results are permission filtered
Nothing in the palette is a shortcut around access control. Every group is filtered before it reaches you:
- Products, projects and environments are fetched through the same list endpoints the rest of the dashboard uses. Each requires the matching read permission (
products:read,projects:read,environments:read); without it the request is refused with401and that group is simply empty. - Those endpoints then drop anything inside a private product you have not been granted. Any role carrying
products:manage_private, which owners and admins both do, is unrestricted. Everyone else sees every product that is not private plus the private ones granted to them, and a project or environment under a product you cannot reach never enters the result set. - Page entries carrying a permission are dropped when your role does not hold it, so Team is absent without
members:read, Billing withoutbilling:read, Keys withoutkeys:read, Webhooks withoutwebhooks:readand Products withoutproducts:read. Settings, Roles, Encryption, CI / Machine Access and Virtual Envs carry no permission and are always listed.
Which pages are listed
The workspace level pages are always candidates. Product, project and environment pages are added only when the URL you are on already carries the slugs needed to build them, because an entry whose path still contains an unresolved :param is discarded rather than guessed at:
| You are on | Pages added |
|---|---|
| Any dashboard page | Products, Team, Billing, Keys, Webhooks, Settings, Roles, Encryption, CI / Machine Access, Virtual Envs |
| A product URL | Product projects, Product settings |
| A project URL | Project environments, Project settings (plus the product ones) |
| An environment URL | Environment variables, Environment versions, Environment settings (plus the product and project ones) |
Scoped entries are titled with their group in front, so you search for environment versions rather than versions. Duplicate destinations collapse to the first one that claimed the URL, which is why /settings appears once as Settings and not again as Workspace. Every Back to ... nav entry is skipped.
What the palette does not do
It is a navigator, not a command runner. It has no actions in it: nothing in the list creates, publishes, toggles or deletes anything, selecting a result only routes you to a page. It also does not search:
- Variable names or values. Values are ciphertext the server cannot read, and names are not indexed here either. Search variables from the environment page itself, covered in Variables in the dashboard.
- Versions, including version labels and notes.
- Team members, roles, API keys, webhooks or invoices.
- Workspaces. The palette only ever covers the workspace you are currently in. Switching workspaces is
⌘ 1to⌘ 9or the switcher menu. - Pages that are not in the sidebar navigation, which means Account, Preferences, CLIs, Billing invoices, the raw
.enveditor and a specific version's page are unreachable from the palette even though they exist.
The preview pane on the right is hidden below the md breakpoint, so on a narrow window the palette is the result list alone. The highlight also follows the mouse, so moving the pointer across the list changes what ↵ will open.
The create shortcut
c is context aware: exactly one create action is armed per page, and pressing c runs whichever one it is. No modifier is involved, and the handler returns immediately if meta, control or alt is held, so ⌘ C stays copy. Shift is not excluded, so a capital C triggers it too.
| Page | c opens | Needs |
|---|---|---|
| Products | Create product | products:create |
| A product | Create project | projects:create |
| A project | Create environment | environments:create, project not locked |
| An environment (table view) | Add variables | variables:create, project not locked |
| Team | Invite member | members:invite |
| Keys | Create key | keys:create |
| Roles | Create role | roles:create |
| Webhooks | Create webhook | webhooks:create |
Everywhere else, including the workspace, product, project and environment settings pages, the versions page and the billing pages, c is not bound and does nothing. Roles is the one settings page that binds it.
Two surfaces have an extra condition. On a product, c opens the plan limit modal instead of the create modal when the workspace is already at its project cap, and it does nothing at all until a project list has landed in the cache, because that cached list is what the cap is counted from. On an environment, c is armed only on the table view: adding /raw to the URL for the raw editor disarms it, and it stays inert until the project and environment ids have loaded.
When c and p are ignored
Both shortcuts share the same guards, and both are silent rather than loud when a guard trips:
- Focus is in an
input,textarea,selector anycontenteditableelement, or inside an element with theswitch,checkbox,radio,textbox,searchboxorspinbuttonrole. - Focus is inside an open popup: a listbox, a menu, a menu item, an expanded combobox, or any element advertising an expanded popup of its own.
- Any overlay is open anywhere on the page: a dialog, a sheet, a drawer, the command palette, an open select, or an open dropdown menu. So
cwill not stack a second modal on the one you already have. - Meta, control or alt is held.
- More than one handler is registered at once. The shortcut is registered globally and is only fired when exactly one page has claimed it, so if two ever overlap, neither runs. In development that also logs an error naming the count.
The publish shortcut
p opens the Publish version modal, and it is bound on the environment table view and nowhere else in the app. It needs more than the create shortcut does: both variables:create and versions:create, an unlocked project, the table view rather than /raw, loaded project and environment ids, and the environment's variables query already settled. Until all of those hold, the key does nothing. The Publish button in the page header draws its P hint the whole time the button exists, so the hint on its own proves nothing. The button is disabled in exactly the states that keep the shortcut dead, so an enabled Publish button is the reliable tell.
Switching with ⌘ 1 to ⌘ 9
The sidebar renders exactly one switcher at a time, chosen by how deep the current URL is, and the number keys are bound by whichever switcher that is. The same keystroke therefore means four different things depending on where you are:
| Current URL | Switcher shown | ⌘ 1 to ⌘ 9 |
|---|---|---|
| Anything not under a product (Products, Team, Keys, Webhooks, Billing, Settings) | Workspace | Switches the active workspace in place, without navigating |
/products/<product-slug> and its settings | Product | Opens the nth product |
/products/<product-slug>/projects/<slug> and its settings | Project | Opens the nth project in the whole workspace, not just the current product |
| An environment URL | Environment | Opens the nth environment of the current project |
The numbering always matches the order shown in that switcher's dropdown, because both read the same cached list. Products, projects and environments are listed alphabetically by name. Workspaces come back in whatever order the API returns them, so read the numbers off the menu rather than assuming.
Only the first nine entries are addressable, and only those nine are drawn with a number in the menu. A tenth product or environment has no shortcut and has to be clicked. Pressing a number with nothing at that position does nothing at all.
These four handlers have none of the guards that c and p have. They fire while you are typing in a text field and while a modal, a sheet or the command palette is open, so ⌘ 3 in the middle of editing a variable name will navigate away from the page. Envless does call preventDefault on the event, but a browser that reserves ⌘ 1 to ⌘ 9 for its own tab switching may claim the combination first; the switcher menu is always there as the fallback.
Switching a workspace is the one case that does not navigate. It swaps the selected workspace in place and resets the workspace scoped state. If the request fails, the previous workspace is restored and an error toast explains why. Note that the workspace key is per workspace, so after switching you may need to unlock again at Settings, Encryption. See Choosing a passphrase.