Create a View
Viewkit is a CLI tool that helps you initialize, manage, and publish Shinzo views. In this guide we're going to build and install the viewkit executable, create a view, and publish it to the testnet. If you'd rather work from a browser UI instead of the CLI, Shinzo Studio covers the same create โ deploy โ query flow for Views.
Prerequisites
- Git
- Make
- Go 1.25
Setup
-
Make sure you've got all the prerequisites installed properly:
git --version && make --version && go versiongit version 2.43.0 GNU Make 4.3 [...] go version go1.25.12 linux/arm64 -
Clone the repository:
git clone https://github.com/shinzonetwork/shinzo-view-creator.git cd shinzo-view-creator -
Build the Viewkit binary:
make buildYou should see a
builddirectory: -
Run Viewkit:
./build/viewkit --helpViewkit helps you initialize, manage, and publish Shinzo views through a simple CLI interface. Usage: viewkit [command] [...] -
Move the
viewkitexecutable somewhere reasonable (optional):sudo mv ./build/viewkit /usr/local/binNow you can run
viewkitfrom anywhere.
Wasmer runtime
Viewkit can execute WebAssembly lenses locally to validate and preview them.
Under the hood, it uses wasmer-go, which depends on a native dynamic library (libwasmer.dylib). If your local system cannot find that library, any command that touches lenses will fail with an error like:
image not found
library not loaded: libwasmer.dylib
-
Move back into the shinzo-view-creator repo if you moved out of it:
cd shinzo-view-creator -
Install the Wasmer Go module:
go get github.com/wasmerio/wasmer-go@v1.0.4go: downloading github.com/wasmerio/wasmer-go v1.0.4 go: added github.com/wasmerio/wasmer-go v1.0.4This makes
wasmer-goand its packaged native libraries available in yourGOPATH.
Environment variables
We need to set three new environment variables:
WASMER_ROOT: points to the directory wherelibwasmer.dyliblives.WASMER_LIB_PATH: used bywasmer-goto find the dynamic library.DYLD_LIBRARY_PATH: MacOS-specific dynamic loader search path. We prependWASMER_ROOTso the loader can findlibwasmer.dylibwhenviewkitstarts.
-
Append these lines to your shell's RC file.
MacOS:
echo 'export WASMER_ROOT="$(go env GOPATH)/pkg/mod/github.com/wasmerio/wasmer-go@v1.0.4/wasmer/packaged/lib/darwin-aarch64"' >> ~/.zshrc echo 'export WASMER_LIB_PATH="$WASMER_ROOT"' >> ~/.zshrc echo 'export DYLD_LIBRARY_PATH="$WASMER_ROOT:$DYLD_LIBRARY_PATH"' >> ~/.zshrcLinux:
echo 'export WASMER_ROOT="$(go env GOPATH)/pkg/mod/github.com/wasmerio/wasmer-go@v1.0.4/wasmer/packaged/lib/linux-amd64"' >> ~/.zshrc echo 'export WASMER_LIB_PATH="$WASMER_ROOT"' >> ~/.zshrc echo 'export LD_LIBRARY_PATH="$WASMER_ROOT:$LD_LIBRARY_PATH"' >> ~/.zshrc -
Reload your shell configuration:
source ~/.zshrc -
Verify that the variables are set:
echo "$WASMER_ROOT" ls "$WASMER_ROOT"/home/user/go/pkg/mod/github.com/wasmerio/wasmer-go@v1.0.4/wasmer/packaged/lib/linux-amd64 dummy.go libwasmer.so
If libwasmer.dylib is missing, re-run the go get step and ensure go env GOPATH returns a valid path.
Create a view
Now that everything is set up, we can start creating and deploying views.
-
Initialize the view bundle:
viewkit view init testdeploy๐ View: testdeploy ๐ Query: <none> ๐ SDL: <none> ๐ง Lenses: - (empty) ๐ Metadata: - Version: 0 - Total: 0 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:34:27 +0000 UTCThis:
- Creates a new view bundle called
testdeployon disk. - Registers internal metadata for queries, SDL, lenses, and versions.
- Creates a new view bundle called
-
Inspect the bundle:
viewkit view inspect testdeploy๐ View: testdeploy ๐ Query: <none> ๐ SDL: <none> ๐ง Lenses: - (empty) ๐ Metadata: - Version: 0 - Total: 0 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:34:27 +0000 UTC -
Next we're going to add a query (raw ingest shape). First, define the raw data shape to ingest, e.g. raw event logs:
viewkit view add query \ "Log {address topics data transactionHash blockNumber}" \ --name testdeploy๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: <none> ๐ง Lenses: - (empty) ๐ Metadata: - Version: 1 - Total: 1 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:36:32 +0000 UTCThis tells Viewkit that
testdeploywill ingestLogobjects with the specified fields. -
Then, check:
viewkit view inspect testdeploy๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: <none> ๐ง Lenses: - (empty) ๐ Metadata: - Version: 1 - Total: 1 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:36:32 +0000 UTC -
Add an SDL to describe how the data is modeled/exposed:
viewkit view add sdl \ "type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String}" \ --name testdeploy๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String} ๐ง Lenses: - (empty) ๐ Metadata: - Version: 2 - Total: 2 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:37:24 +0000 UTCNote@materialized(if: false): treat this as a virtual type, not a persisted table.transactionHash: String: minimal example field; real views will define more fields.
-
Inspect the view again:
viewkit view inspect testdeploy # now shows both query and SDL๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String} ๐ง Lenses: - (empty) ๐ Metadata: - Version: 2 - Total: 2 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:37:24 +0000 UTCIt now shows both the query and the SDL.
-
Attach a WebAssembly lens that decodes event logs using an ABI. These are the flags we're using:
--args: JSON passed to the lens (here, an ABI definition for the ERC-20Transferevent).--label "decode": human-readable label for the lens.--url: remote URL of the.wasmbinary.--name testdeploy: attaches this lens to thetestdeployview.
viewkit view add lens \ --args '{"abi":"[{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"type\":\"address\",\"name\":\"from\",\"indexed\":true},{\"type\":\"address\",\"name\":\"to\",\"indexed\":true},{\"type\":\"uint256\",\"name\":\"value\",\"indexed\":false}]}]"}' \ --label "decode" \ --url "https://raw.githubusercontent.com/shinzonetwork/wasm-bucket/main/bucket/decode_log/decode_log.wasm" \ --name testdeploy๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String} ๐ง Lenses: - decode (assets/decode.wasm) Arguments: abi: [{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","indexed":true},{"type":"address","name":"to","indexed":true},{"type":"uint256","name":"value","indexed":false}]}] ๐ Metadata: - Version: 3 - Total: 3 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:39:11 +0000 UTC -
Inspect the view again:
viewkit view inspect testdeploy # you should now see: # - query # - SDL # - lens "decode"You should now see the query, SDL, and the
decodelens:๐ View: testdeploy ๐ Query: Log {address topics data transactionHash blockNumber} ๐ SDL: type FilteredAndDecodedLogs @materialized(if: false) {transactionHash: String} ๐ง Lenses: - decode (assets/decode.wasm) Arguments: abi: [{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","indexed":true},{"type":"address","name":"to","indexed":true},{"type":"uint256","name":"value","indexed":false}]}] ๐ Metadata: - Version: 3 - Total: 3 - Created At: 2026-07-09 09:34:27 +0000 UTC - Updated At: 2026-07-09 09:39:11 +0000 UTC
If you see libwasmer.dylib / "image not found" errors, revisit the Wasmer setup.
-
Before deploying, validate that your view builds and compiles successfully:
viewkit view test testdeployThis spins up a temporary local DefraDB instance, applies your schema, runs the lens, and checks that everything compiles. If it passes, your view is ready to deploy.
Create a deployment key
You need a wallet to sign deployments to devnet.
-
Generate a new one:
viewkit wallet generateโ Wallet generated Mnemonic: document grass code lawn erosion climb people sunset three blame balcony story script hip soup lesson resemble above quiz acid dust salmon plane Address: 0x2e4150993E841b38f4780BC158A7dA0d62E22ec9 -
Treat this wallet like any other secret or asset:
- Do not commit it to Git.
- Do not paste the mnemonic in public places.
- Store it securely.
Deploy locally
The recommended flow is to deploy locally first, verify the view in a Playground, then deploy to a shared network.
-
Deploy locally:
viewkit view deploy testdeploy --target local๐ DefraDB is running on port 9181 โณ Waiting for DefraDB to boot up... โ DefraDB booted up โณ Applying Schemas ... โ Schema Applied โณ Data Inserting... โ Data Inserted Successfully โ Applying View ... โ View Successfully Applied ๐งช Visit the DefraDB GraphQL Playground at http://127.0.0.1:9181/ ๐ฆ Press Ctrl+C to stop...Here's what's happening:
- A local DefraDB instance is started (port shown in the logs).
- Schemas for your view are applied.
- Any seed data (if configured) is inserted.
- The view is applied.
- A DefraDB GraphQL Playground URL is printed.
Use the DefraDB GraphQL Playground
This section is optional, but it's a good idea to check the View within the built-in GraphQL Playground.
- Open the displayed URL in your browser, usually 127.0.0.1:9181.
- You should see a GraphQL Playground.
- Within this Playground you can:
- Inspect the schema (e.g. see
FilteredAndDecodedLogs). - Run test queries against your local view.
- Verify that your lens is filtering logs as expected.
- Inspect the schema (e.g. see
For example, you can run a query like:
{
filteredAndDecodedLogs {
transactionHash
}
}
While this process is running, viewkit will keep the local DefraDB instance alive. Press CTRL + c to stop the DefraDB instance.
Deploy to devnet
Once your view behaves correctly locally, you can deploy it to a shared network.
-
Gather an RPC URL.
-
Deploy the view to the network:
viewkit view deploy testdeploy --target devnet --rpc http://testnet.shinzo.network:8545/
More examples
For progressively more complex View examples (decoding multiple event types, transaction-based views without lenses, materialized vs on-query views, editing and rolling back views), see the View examples page, which includes both the view definitions and the GraphQL queries you run against them.
For the conceptual overview, see Views for builders. For the full command list, filter operators, VWL wire format, and deploy internals, see the Viewkit reference. For a deeper dive on lenses, available modules, and how to chain them, see the Lens reference. For troubleshooting and common errors, see Operations: Troubleshooting.
Need help
- For onboarding and technical support, join the Shinzo Discord.
- To report a documentation bug or request a feature, open an issue in the docs repo.
- For a technical issue with the Viewkit client, open an issue in the shinzo-view-creator repo.