
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
@graphiql/plugin-collections
Advanced tools
A first-party operation collections plugin for GraphiQL. Save named GraphQL operations into collections and reuse them later, with drag-and-drop reordering, clipboard sharing, and JSON import/export that merges by id instead of duplicating.
npm install @graphiql/plugin-collections
Make sure the peer dependencies are installed too:
npm install react react-dom graphql @graphiql/react
The collections plugin is installed by default in GraphiQL, so an unmodified <GraphiQL> already shows a Collections rail icon. You only need to register it explicitly to configure it, for example to supply a custom storage backend or restrict what users can do.
Note: passing the
pluginsprop replaces the default plugin set, so include the others you want alongside it.
import { GraphiQL } from 'graphiql';
import { createTransport } from '@graphiql/toolkit';
import { collectionsPlugin } from '@graphiql/plugin-collections';
import 'graphiql/style.css';
import '@graphiql/plugin-collections/style.css';
const transport = createTransport({
url: 'https://swapi-graphql.netlify.app/.netlify/functions/index',
});
const collections = collectionsPlugin();
function GraphiQLWithCollections() {
return <GraphiQL transport={transport} plugins={[collections]} />;
}
collectionsPlugin({
storage, // custom persistence backend; see below
readOnly, // default false
allowImportExport, // default true
allowReplace, // default true
});
| Option | Default | Effect |
|---|---|---|
storage | localStorage adapter | A custom CollectionsStorage (see Custom storage). |
readOnly | false | Hides every write affordance (create, rename, delete, reorder, save, import). Export and copy stay available so users can still share. |
allowImportExport | true | When false, hides the import/export dialog button and turns off paste/drop import. |
allowReplace | true | When false, hides the destructive "replace everything" import mode and leaves only merge. |
Collections and the operations inside them carry stable UUIDs that survive export and import. On import, the plugin reconciles by id instead of duplicating:
An operation can also be shared on its own with "Copy operation". It travels as a one-item collection envelope stamped with its parent collection, so the recipient can re-home it on import.
Persistence is pluggable through the CollectionsStorage interface:
type CollectionsStorage = {
storageKey?: string;
load(): Promise<Collection[]>;
save(collections: Collection[]): Promise<void>;
};
The default writes to localStorage under the key graphiql:collections. To use a different key, pass an adapter from the exported createLocalStorageAdapter factory:
import {
collectionsPlugin,
createLocalStorageAdapter,
} from '@graphiql/plugin-collections';
const collections = collectionsPlugin({
storage: createLocalStorageAdapter('my-key'),
});
To back collections with your own service (REST, a database, a team-shared store), implement the interface and pass it as storage:
import { collectionsPlugin } from '@graphiql/plugin-collections';
import type {
Collection,
CollectionsStorage,
} from '@graphiql/plugin-collections';
const apiStorage: CollectionsStorage = {
async load() {
const res = await fetch('/api/collections');
return (await res.json()) as Collection[];
},
async save(collections) {
await fetch('/api/collections', {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(collections),
});
},
};
const collections = collectionsPlugin({ storage: apiStorage });
load() runs once when the panel first mounts. save() runs after every mutation with the full collection list.
The plugin has no opinion about conflict resolution or synchronization; that lives in your storage adapter. Because every operation and collection has a stable id, your adapter can diff successive save() snapshots and reconcile them however it needs to, whether that is a plain backend write, a last-write-wins policy, or a CRDT such as Yjs or Automerge. The plugin itself stays a CRUD UI over a serializable model.
The plugin does not react to remote changes on its own. When your backend reports an external change, call reload() to re-read storage and refresh the UI:
import { collectionsStore } from '@graphiql/plugin-collections';
await collectionsStore.getState().actions.reload();
The store and its React hook are exported for programmatic access:
import {
collectionsStore, // the vanilla zustand store
useCollectionsStore, // React hook: useCollectionsStore(selector)
} from '@graphiql/plugin-collections';
const { actions } = collectionsStore.getState();
// Replace the in-memory collections (e.g. after merging remote state).
// Does NOT write back to storage.
actions.setCollections(nextCollections);
// Re-read from the configured storage and refresh the UI.
await actions.reload();
actions also exposes the full CRUD surface (createCollection, addItem, updateItem, deleteItem, moveItem, renameCollection, and so on) plus exportCollections / exportCollection / exportItem and the two-phase analyzeImport / applyImport.
collectionsPlugin(options?) — the plugin factorycollectionsStore, useCollectionsStore — the store and its React hookcreateLocalStorageAdapter(key), localStorageAdapter — built-in storageCollectionsSaveDialog — the save dialog componentCollection, CollectionItem, CollectionsStorage, CollectionsConfig, ActiveOperationFAQs
Unknown package
The npm package @graphiql/plugin-collections receives a total of 2 weekly downloads. As such, @graphiql/plugin-collections popularity was classified as not popular.
We found that @graphiql/plugin-collections demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.