# Best Practices for Developing with Stremio-Web: A Complete Guide

> Master stremio web development with our guide covering Component-Context-Service architecture, useServices hook, declarative routing, and src core isolation. Optimize your stremio web projects today.

- Repository: [Stremio/stremio-web](https://github.com/Stremio/stremio-web)
- Tags: best-practices
- Published: 2026-05-23

---

**Stremio-web development follows a strict Component-Context-Service architecture that mandates dependency injection through the `useServices` hook, declarative routing via centralized configuration files, and strict isolation of core logic within the `src/core/` directory.**

Stremio-web is the modern React-based frontend for the Stremio streaming platform. Following the established patterns in the `Stremio/stremio-web` repository ensures your contributions remain maintainable, testable, and consistent with the existing architecture. This guide covers the essential conventions for service injection, routing, internationalization, and build tooling based on the actual source code implementation.

## Follow the Component-Context-Service Pattern

The codebase enforces a clear separation of concerns across three layers. **UI components** should never directly import service clients; instead, they consume dependencies through the `ServicesContext` provided by [`ServicesProvider.js`](https://github.com/Stremio/stremio-web/blob/main/ServicesProvider.js) located at [`src/services/ServicesContext/ServicesProvider.js`](https://github.com/Stremio/stremio-web/blob/main/src/services/ServicesContext/ServicesProvider.js).

The context definition in [`src/services/ServicesContext/ServicesContext.js`](https://github.com/Stremio/stremio-web/blob/main/src/services/ServicesContext/ServicesContext.js) establishes the contract for all runtime services. When adding new API clients or utilities, register them in the services index and pass them through the provider rather than using module-level imports. This guarantees that the dependency graph remains explicit and facilitates mocking during testing.

## Use the useServices Hook for Type-Safe Access

Always access injected services through the `useServices` hook defined in [`src/services/ServicesContext/useServices.js`](https://github.com/Stremio/stremio-web/blob/main/src/services/ServicesContext/useServices.js). This hook provides compile-time safety via TypeScript typings and ensures components receive the correct service instances from the context.

**Never import the provider directly** into presentational components. The hook abstraction allows the testing framework to substitute mock services easily without modifying component code. The hook implementation guarantees that services are available or throws a descriptive error if used outside the provider tree.

## Configure Routes Declaratively in Centralized Files

The routing system relies on configuration objects rather than inline JSX routes. Define new URL patterns in [`src/router/Router/routeConfigForPath.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/routeConfigForPath.js), which maps paths to lazy-loaded view components. The `Router` component at [`src/router/Router/Router.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/Router.js) consumes this configuration to handle navigation and code splitting automatically.

For URL parameter parsing, maintain the mapping logic in [`src/router/Router/urlParamsForPath.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/urlParamsForPath.js). This separation prevents duplicate regex patterns scattered across components and ensures consistent parameter extraction. When adding a view, update only the route configuration and the lazy import statement—never implement manual URL parsing logic inside components.

## Manage Modals Through ModalsContainerContext

Modal handling is centralized via `ModalsContainerContext` to ensure proper stacking and unmounting behavior. Implement modal providers using the pattern established in [`src/router/ModalsContainerContext/ModalsContainerProvider.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/ModalsContainerContext/ModalsContainerProvider.js). 

When a view requires modal functionality, wrap it with the appropriate context provider rather than managing local modal state. This approach guarantees that multiple modals stack correctly and that background scrolling locks properly across different view hierarchies.

## Isolate Core Logic in the src/core/ Directory

The low-level Stremio engine integration lives under `src/core/` and exposes its API through `CoreProvider`, instantiated in [`src/index.js`](https://github.com/Stremio/stremio-web/blob/main/src/index.js). Keep all core-related business logic strictly within this directory to prevent leakage into UI components.

Components should interact with core functionality through the `CoreContext` defined in [`src/core/CoreContext.ts`](https://github.com/Stremio/stremio-web/blob/main/src/core/CoreContext.ts) rather than instantiating core objects directly. This isolation ensures that the React layer remains agnostic of the underlying Stremio engine implementation details, making future core updates backward-compatible with the UI layer.

## Initialize Internationalization at Bootstrap

The application loads translations through the `stremio-translations` bundle during startup. In [`src/index.js`](https://github.com/Stremio/stremio-web/blob/main/src/index.js), the i18n initialization occurs before the React tree renders. All user-facing strings must be added through this mechanism to ensure synchronization across supported languages.

Avoid hard-coding English strings in components. Instead, use the translation keys provided by the bundle. This guarantees that community translations remain in sync and that the interface respects user locale preferences automatically.

## Adhere to pnpm and Webpack Tooling Standards

The project uses **pnpm** exclusively for package management, as specified in [`package.json`](https://github.com/Stremio/stremio-web/blob/main/package.json) and the `Dockerfile`. Use `pnpm install` to populate dependencies and avoid mixing npm or yarn to prevent lock-file inconsistencies.

Webpack handles bundling with scripts defined in [`package.json`](https://github.com/Stremio/stremio-web/blob/main/package.json). Use `pnpm start` for local development with hot reloading and `pnpm run build` for production optimization. The provided `Dockerfile` at the repository root ensures reproducible production deployments.

## Implement Environment Safety Checks

Sensitive configuration values such as `SENTRY_DSN` are read from `process.env` only after runtime type validation (`typeof … === 'string'`). Never hard-code API keys or secrets in source files. Configure CI pipelines to inject environment variables during build time, and add fallbacks for missing optional variables to prevent runtime crashes.

## Write Jest Tests Alongside Features

Unit tests reside under the `tests/` directory and run via Jest. Create test files adjacent to the modules they validate, following the naming convention `[feature].test.js` or `[feature].spec.js` as seen in [`tests/routesRegexp.spec.js`](https://github.com/Stremio/stremio-web/blob/main/tests/routesRegexp.spec.js).

Mock external dependencies aggressively to ensure tests run quickly and deterministically. The `useServices` hook architecture makes this straightforward by allowing injection of mock service objects. Always run `pnpm test` before committing to verify that new functionality does not introduce regressions.

## Maintain Code Quality with ESLint

The project uses ESLint configured in `eslint.config.mjs` for static analysis. Run `pnpm lint` locally to catch style violations before submitting pull requests. The configuration enforces consistent formatting and catches common React anti-patterns, such as missing hook dependencies or improper prop-types usage.

## Summary

- **Inject dependencies** through `ServicesProvider` and consume them via `useServices` to maintain testable architecture.
- **Configure routes** in [`src/router/Router/routeConfigForPath.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/routeConfigForPath.js) using the declarative pattern rather than manual URL parsing.
- **Isolate core logic** within `src/core/` and access it through `CoreContext` to keep UI components decoupled from engine internals.
- **Use pnpm exclusively** for package management and follow the Docker-based deployment path for production consistency.
- **Validate environment variables** with type checks before use and never commit secrets to the repository.
- **Write Jest tests** for new services and utility functions, mocking external APIs to ensure fast, reliable CI passes.

## Frequently Asked Questions

### How do I add a new API service to stremio-web?

Create the service class in `src/services/`, export it from [`src/services/index.js`](https://github.com/Stremio/stremio-web/blob/main/src/services/index.js), and register it in the services object passed to `ServicesProvider`. Access the service in components using the `useServices` hook rather than importing the class directly. This pattern ensures type safety and simplifies unit testing by allowing mock injection.

### What is the correct way to add a new page or route?

Define the route pattern and lazy-loaded component in [`src/router/Router/routeConfigForPath.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/routeConfigForPath.js). If the route accepts URL parameters, update [`src/router/Router/urlParamsForPath.js`](https://github.com/Stremio/stremio-web/blob/main/src/router/Router/urlParamsForPath.js) with the extraction logic. The `Router` component handles the mapping automatically, so you never need to parse `window.location` manually inside view components.

### How does stremio-web handle translations and localization?

The application initializes the `stremio-translations` bundle in [`src/index.js`](https://github.com/Stremio/stremio-web/blob/main/src/index.js) before mounting the React tree. All user-facing strings must reference keys from this bundle rather than hard-coded text. This ensures automatic synchronization when community translators update language packs, and respects the user's selected locale without additional component logic.

### Why must core logic stay isolated in the src/core/ directory?

The `src/core/` directory contains the low-level Stremio engine integration that manages streaming protocols and metadata parsing. Keeping this logic isolated prevents UI components from becoming coupled to engine implementation details, allowing the core to update independently. Components should interact with core functionality exclusively through `CoreContext` and `CoreProvider` abstractions.