Thinking in Hiro
Hiro solves the problem of rebuilding common metagame systems for every social or live service game. Instead of programming achievements, economies, and leaderboards from scratch, Hiro provides pre-built systems that work through configuration.
Hiro’s design reflects a deliberate philosophy: provide working systems that require minimal intervention, but make advanced features available for developers who need them. You don’t need to understand Hiro’s internals to get value from it. The systems work out of the box with sensible defaults that handle common use cases automatically. As you need more sophistication, you can gradually learn and apply advanced features without rewriting what you’ve already built.
This article explains the design principles behind Hiro. You’ll see how Hiro fits into the broader evolution of game development concerns, why we’ve taken a configuration-first approach to its design, and how Hiro separates data definitions from player state.
Layers of a live game #
Building an online game means solving problems at multiple layers. At the infrastructure layer, you need networking, authentication, and data storage. At the logic layer, you need game rules and behaviors. At the metagame layer, you need economies, progression, leaderboards, and more. Finally, with everything else in place, you need to be able to tune and personalize content to meet the demands of operating live games.
Each layer has been solved at Heroic Labs, leaving you to focus on what makes your game unique. The core principle that has driven the evolution of our game technology is to move problems to higher, more domain-specific levels. As a result, at each layer you write less implementation code and work more with configuration.
Networking and infrastructure #
At the base level, you need network protocols, authentication, data persistence, security, and scalable server architecture. Building these from scratch means dealing with:
- Socket management and protocol handling
- Authentication and session systems
- Database architecture and security
- Scaling and server deployment
Nakama and Heroic Cloud solve this layer by providing the foundational infrastructure (authentication, database layers, real-time networking, and matchmaking) so you don’t have to build or maintain them.
Custom game logic #
With infrastructure handled, you still need server logic for your game: custom matchmaking algorithms, tournament bracket management, economy validation, or anti-cheat systems.
The Nakama runtime solves this layer by letting you write server-side code to validate game state, manage multiplayer sessions, and enforce rules without building the backend infrastructure from scratch.
Metagame systems #
Even with the first two layers handled, most games still rebuild the same metagame systems:
- Achievement tracking and progression
- Virtual stores and currencies
- Event leaderboards
- And many more
These systems are well-understood patterns that don’t need to be coded from scratch for every game. The rules and behaviors are consistent across games.
Hiro solves this layer by providing pre-built, tested systems that you configure instead of code. All you have to do is define the specifics for your game.
Customization and LiveOps #
Once your systems are running, you need to personalize content for different player segments. Static configuration requires new deployments for every change, creating bottlenecks. But eliminating configuration entirely would create a rigid system that works only one way for everyone.
Hiro Personalizers and Satori solve this layer by making configuration dynamic, contextual, and personalized per player. You can run A/B tests, customize content for different player segments, and respond to analytics in real-time. Static configurations can be overridden at runtime based on player attributes, game client versions, live event schedules, and other criteria you define.
Configuration over code #
This progression through layers reveals something important: you can’t get rid of configuration. The diversity and variation that makes games interesting requires configuration. Hiro leans into this principle by making configuration domain-specific. This design decision shapes how you work with every system and provides significant advantages over pure code-based approaches.
Consistent structure across systems #
Each Hiro system uses JSON configuration to define its behavior. The structure is consistent across systems, whether you’re configuring Achievements, Inventory, Economy, or Event Leaderboards. This makes it easy to learn one system and apply that knowledge to others. See Hiro configuration for more examples.
Progressive enhancement #
Start with static JSON files deployed with your game server and add dynamic configuration later as needed. The Personalizer acts like middleware, creating a pipeline where each data source can inspect and modify configuration before it reaches the game systems:
| |
Each stage can add new items, modify existing properties, or leave configuration unchanged. Later stages override earlier ones, creating increasing levels of customization. Read more about the Personalizer.
Data definitions and player state #
Every Hiro system works with two fundamentally different types of content: data definitions and player state.
Data definitions describe what exists in your game world: the rules, available content, and system behaviors. These are the achievements players can earn, the items they can collect, how fast energy refills, what rewards are possible, and store item prices and availability. Data definitions describe what’s possible for players and remain consistent across function calls for a given player context until you update the configuration.
Data definitions live in static JSON files in your game module, though they can also be pulled from dynamic sources through the Personalizer.
Player state, in contrast, represents what each individual player has achieved, owns, or has progressed toward. This includes achievement progress, inventory contents, current energy levels, currency balances, and team membership. Player state is unique to each player and updates as they play.
When you call a Hiro API like GetAchievements(), Hiro fetches the data definitions from your configuration sources, fetches the player’s state from Nakama storage, and merges them together. The response shows you all the achievements the player can see along with their progress on each one.
This separation matters because it lets you focus on designing your game systems without worrying about how individual player progress is tracked and stored. The API handles the complexity of merging configuration with state, so you work with complete, ready-to-use data rather than stitching together multiple data sources yourself. You think about what achievements exist and how they work, not about database schemas or storage implementation details.
How definitions and state work together #
Consider a simple achievement. The data definition specifies the achievement’s ID, name, description, maximum count, and rewards:
| |
This definition exists in your configuration and is the same for all players. It defines what the achievement is and what’s required to complete it.
The player state tracks this specific player’s progress:
| |
This state is stored in Nakama’s storage for this player’s user ID. It shows they haven’t yet completed the achievement.
When the client calls GetAchievements(), Hiro merges these together:
| |
The client receives everything it needs: what the achievement is (from the definition) and how far along the player is (from their state).
Separation of concerns #
This separation matters because the Personalizer only affects data definitions (what content exists), never player state. A definition might come from Satori, but the player’s progress on that achievement is tracked in Nakama. This maintains a clear separation of concerns: Satori manages dynamic configuration and audience targeting, while Nakama serves as the authoritative game backend storing all player data.
This separation prevents confusion that can occur in other platforms where LiveOps tooling and game backend responsibilities are blurred. In Hiro’s architecture, you configure definitions through JSON or Personalizers, while the server tracks player state as players interact with your systems.
Key takeaways #
Sensible defaults: Systems work out of the box with minimal intervention. Advanced features are available when needed, letting you learn gradually without rewriting what you’ve built.
Progressive abstraction: The Heroic tech stack solves common game development issues at four layers: infrastructure, custom logic, metagame systems, and customization. At each layer, you write less implementation code and work more with configuration.
Configuration-first approach: Hiro takes a configuration-first approach with consistent JSON structure across all systems and progressive enhancement through Personalizers.
Separation of concerns: Data definitions describe what exists in your game world. Player state tracks individual progress. Hiro APIs merge these automatically, letting you focus on game design without managing storage details.
