How to create VTEX IO apps: practical developer guide
VTEX IO apps are the official way to extend the VTEX platform. From visual storefront components to backends with custom APIs, the app system allows creating features that the standard ecosystem does not cover. This guide covers the entire process: from initial setup to production deployment, focusing on TypeScript best practices, performance and maintainability.
Development environment setup
The first step is installing the VTEX CLI globally via npm: npm install -g vtex. Then authenticate with vtex login your-account. Create a development workspace with vtex use workspace-name. The workspace isolates your changes from the production environment. Check your Node.js version (recommended 18+) and install Yarn as package manager. To create a new app, use vtex init and select the appropriate template (react, node, service, or graphql). The template generates the base structure with manifest.json, builder directory and initial configurations. From there, vtex link connects your local code to the workspace with hot reload.
VTEX IO app structure
Every VTEX IO app has a manifest.json at the root. This file defines: vendor (owner account), name (unique identifier), version (semver), builders (which builders the app uses), dependencies (apps this app consumes), policies (access permissions to APIs and services). Builders determine the directory structure. An app with the react builder will have a react/ directory with TypeScript/React components. An app with the node builder will have node/ with middleware and services. An app with the graphql builder will have graphql/ with schemas and resolvers. An app can combine multiple builders. Example: a reviews app might have react/ for the visual component, node/ for the backend that persists data and graphql/ for the API connecting both.
React builder: storefront components
The react builder allows creating components that appear in the store. The component is a React function component exported as default. The store/interfaces.json file declares the block for Store Framework: block name, component it renders and property schema. Props are defined via JSON Schema and appear in the Site Editor (visual admin). For styling, use CSS Modules or the CSS Handles API to allow external customization. Avoid inline styles and global styles. Use strict TypeScript: define interfaces for props, avoid any and validate API data with type guards. Each component should be focused: one block, one responsibility. Large components should be split into internal sub-components.
Node builder: backend and services
The node builder creates Express-like backends that run on the VTEX IO runtime. The entry point is node/index.ts which exports a Service object with routes and handlers. Each handler receives ctx (context) with methods to access VTEX internal APIs (catalog, checkout, OMS), make external calls and manipulate cache. Common use cases: integration middleware with external APIs, webhook processing, scheduled tasks (schedulers) and custom endpoints for the frontend. Use TypeScript for the entire backend. Define interfaces for input and output payloads. Handle errors with try/catch and return semantic status codes. Configure cache appropriately: routes that do not change frequently should have aggressive cache to reduce latency.
GraphQL builder: typed APIs
The graphql builder exposes GraphQL APIs for the store. The graphql/schema.graphql file defines types, queries and mutations. Resolvers in graphql/resolvers/ implement the logic. Queries are consumed by the frontend via useQuery hooks from react-apollo. VTEX IO GraphQL supports cache directives (@cacheControl) that determine how long the response stays cached. Use maxAge and scope to control invalidation. For queries that fetch rarely-changing data (configurations, static lists), configure long cache. For user-dependent queries (cart, wishlist), use scope PRIVATE without cache.
Testing and quality
VTEX IO apps support unit testing with Jest. Configure jest.config.js in the builder directory (react/jest.config.js or node/jest.config.js). For React components, use React Testing Library. For the Node backend, test handlers in isolation by mocking ctx. Beyond unit tests, manually validate the app in the workspace before publishing. Use vtex link and navigate the store testing all scenarios. Check performance with Lighthouse before and after installing the app. Each app adds bundle weight; monitor the impact. Use ESLint with strict TypeScript rules. Configure lint as a CI step to ensure quality on every commit.
Deploy and publishing
The publishing cycle follows: local development with vtex link, workspace testing with vtex deploy, registry publishing with vtex publish. After publishing, the app becomes available for installation via vtex install vendor.app-name@version. For internal apps (not published to marketplace), vtex deploy on the production workspace (master) is sufficient. For distributed apps, vtex publish registers the version and makes it accessible to other accounts. Versioning follows semver: patch for fixes, minor for backward-compatible features, major for breaking changes. Maintain a CHANGELOG and document breaking changes clearly. Use vtex release to automate version bump, git tag and publishing in one command.
Best practices and common mistakes
Keep apps small and focused. An app that does everything becomes a monolith that is hard to maintain. Declare only necessary policies in manifest.json: principle of least privilege. Do not make waterfall requests in the backend: use Promise.all for parallel calls. Do not store secrets in code: use VTEX Settings or workspace environment variables. Avoid N+1 GraphQL queries: fetch data in batches when possible. Do not ignore TypeScript errors with ts-ignore: fix the type. Monitor response time of your routes: slow endpoints degrade user experience. And most importantly: before creating an app, check if the problem already has a solution in the marketplace.