Setting Up Pulumi for Infrastructure as Code

Infrastructure built manually breaks at the first change and slows down the release of updates. We set up Pulumi turnkey: we describe environments as code so that deployment and recovery take minutes, not days. We'll discuss your task and come back with an estimate and a plan.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Frequently Asked Questions

Setting Up Pulumi: Where Infrastructure Breaks

Infrastructure assembled by hand doesn't break at the moment of change, but months later — when the gap between what's documented and what's actually running becomes critical.

The classic scenario: a staging environment was spun up "in the image of" production, but somewhere along the way someone opened a port, changed limits, or added a load balancer rule — and now the reproducibility of environments rests on one engineer's memory.

Configuration drift accumulates quietly: every manual intervention leaves a trace that's invisible in review or version control until it hits an incident.

The cost of this approach shows up in two places. First — recovery: when you need to spin up a copy of an environment or roll back after a failed release, it turns out there's no precise description of the state, just a set of half-forgotten steps.

Second — changes: an edit that's safe on staging produces a different result in production, because the environments diverged long ago.

Manual infrastructure management shifts risk from process to people — and that's the most expensive class of failure, because it surfaces at the most inconvenient moment.

Infrastructure as code eliminates this class of failure by design: the environment description lives in a repository, every change goes through review, and state is reconciled against the declared configuration on every apply.

Setting up Pulumi here provides what declarative descriptions lack — a familiar programming language instead of a separate dialect: loops, conditionals, reusable modules, and typing, which means the configuration reads like ordinary code and passes the same checks.

The practical effect is predictability.

A new environment spins up with a single command from the same description as the rest, divergences are visible before apply, and a rollback restores the recorded state rather than "roughly how it was." Let's break down how this is handled in practice: from project structure and environment separation to working with secrets and pre-apply checks.

What managed infrastructure delivers

Deployment speed and release predictability

Infrastructure described as code is deployed entirely from a repository: the environment comes up repeatably, not "the way it was on prod last time." The same set of descriptions produces an identical result on the test contour and in the production environment — discrepancies between them stop being a source of surprises.

The speed of deploying a new environment is measured in minutes, not in days of approvals and manual connections.

Recovery time and reduction of manual operations

When configuration lives in a version control system, rolling back to a previous working state is a switch to the required revision, not a recovery from memory.

Recovery time after a failure is reduced to a single run, and the share of manual operations drops: typical changes go through a verifiable set of descriptions rather than through console access.

This eliminates an entire class of failures — a forgotten parameter, a manual edit "on the fly," an undocumented exception.

Eliminated class of failures

Changes go through a preview before being applied: you can see exactly what will be created, changed, or deleted. This is how dangerous edits are caught — accidental deletion of a resource, a change in network rules, a name conflict — before they reach the production environment.

Release predictability grows: every change is reproducible, and the state of the infrastructure can be reconciled with the description at any moment.

Transparency for the team

The history of infrastructure changes reads like the history of code — with an author, a reason, and discussion.

A new engineer joins the project by the descriptions, not by word of mouth, and the review of infrastructure edits follows the same order as the review of an application.

Approaches to describing infrastructure

Infrastructure can be described in three ways, and the choice between them determines how predictably it is reproduced on a new site. Let's break down the options by how they behave as the number of environments grows and when the project is handed over to another team.

Imperative scripts

A set of commands or shell scripts that create resources in order. They are quick to write for a one-off task, but they do not store state: a repeated run either fails or spawns duplicates.

Rollback and reproducing the environment from scratch turn into manual work, and divergence between stands is discovered only in production.

Declarative manifests

State is described by files, and the tool itself brings the system to the desired form. The order of application and repeated runs are safe, and the configuration is versioned alongside the code.

The limitation is its own description language and templating: complex branching and computation logic is expressed cumbersomely, and it has to be kept outside the manifests.

Hybrid approach

Some resources are described declaratively, some — by scripts for migrations and one-off operations. This is reasonable when there is inherited infrastructure, but it requires a strict boundary: what is considered the source of truth and what is a one-off edit. Without this boundary, state diverges, and no one knows which version is the real one.

Option When it fits Limitations
Imperative scripts one-off setup, one-off operations no state, repeated runs are unsafe
Declarative manifests a stable set of resources, versioning its own language, complex logic outside the description
Code in a general-purpose language many environments, computations, reuse discipline in project structure is required
Hybrid inherited infrastructure an explicit source-of-truth boundary is required

Setting up Pulumi closes the weak spot of declarative manifests: infrastructure is described in a general-purpose programming language, so loops, conditions, and reusable modules work without workarounds, and state is stored and compared just as strictly. Next, we break down how this maps onto real environments.

Stages of implementing Pulumi in a project

Implementation begins not with installing the tool, but with taking inventory of what already runs manually.

At this stage it is important to record the actual state, not the desired one: which resources were created through the console, what is described in old templates, where environments diverge. Without this step, any automation cements chaos instead of removing it.

  1. Infrastructure audit. We assemble a complete map of resources, connections, and owners, and reconcile the actual state with what is described in the repositories. We separately flag everything that was created manually and is not reproducible.
  2. Resource schema. We design the project structure: splitting into stacks by areas of responsibility, shared modules, dependencies between components. At this step we decide what is reused and what remains unique to an environment.
  3. Environment setup. We separate configurations for development, testing, and production, and move differences into parameters rather than code copies. Secrets go into a secure vault, and access is divided by roles.
  4. Importing existing resources. We move already-running infrastructure under code management without recreating it — critical services keep running during the migration.
  5. Change verification. Every change goes through a preview of the plan before applying, peer review, and automated checks in the shared branch. Direct edits in the console are closed off so that the state does not diverge from the description.
  6. Documentation handover. We give the customer's team a description of the structure, the change procedure, and the rollback procedure, and we walk through a real task.

After handover, the team makes changes through review and plan preview rather than through the console — discrepancies between environments stop accumulating.

Artifacts and documentation after implementation

After implementation, the team is left not with "contractor magic" but with a working kit: infrastructure code, diagrams, policies, and instructions. Any engineer can open the repository, see how the environment is structured, and reproduce the deployment without us.

  • Configuration as code — a description of all environments (dev/stage/prod) in the repository: network, clusters, databases, load balancers, permissions. Changes go through review and commit history, not through manual edits in a panel.
  • Infrastructure diagrams — an up-to-date map of environments: what connects to what, where network boundaries lie, which services depend on each other. The diagram is updated alongside the code rather than living as a separate outdated file.
  • Access policies — roles and permissions for people and services: who can change what, which actions require confirmation, how access is granted and revoked. The rules are described declaratively and checked automatically.
  • Change procedures — the release process: how a change is prepared, which checks it goes through, how it is rolled back. It is documented what to do in case of a failure and who makes the decision.
  • Instructions for the team — step-by-step guides: how to bring up the environment from scratch, how to add a new service, how to restore the infrastructure after an incident. Designed for an engineer seeing the project for the first time.
  • Secrets and their storage — where keys and passwords are stored, how they are injected during deployment, how they are rotated. No secrets in plaintext in the repository.
  • Handover and training — a session with your team: we go through the repository structure, demonstrate typical scenarios, and answer questions. Ongoing support is not required afterward — you manage the infrastructure yourselves.

The kit stays in your repository and does not depend on us. Describe your task — we will come back with an estimate and a plan of what will be included in the handover.

Case: reducing recovery time

The project was an online ordering platform with three environments and manual deployment: an engineer would bring up an environment using a 40-step checklist, and some of the steps lived only in the heads of two people.

Recovery after a failure took hours, and discrepancies between the test and production environments were discovered only in prod.

We migrated the infrastructure to Pulumi: networks, clusters, databases, and load balancers were described as code in a single repository, state was moved to shared storage with locking, and access was granted through roles.

Changes now go through review in a branch — the deployment plan is visible before it is applied, not after.

Pulumi was chosen because the infrastructure description lives in the same language as the application itself: developers can read it without a separate learning curve, and configuration review follows the same process as code review.

Metrics before and after

Metric Before After
Deploying an environment from scratch 6-8 hours of manual steps 25-30 minutes of automated run
Recovery after a failure 3-4 hours 40 minutes
Incidents caused by environment drift 5-7 per quarter 1 in six months
Rollback to a previous version manually, from memory one command in 10 minutes

The key effect is not speed as such, but predictability: recovery no longer depends on which engineer is on call. The share of incidents resolved by rollback without manual fixes grew from isolated cases to the majority — an outage is no longer a half-day event.

We also documented the rules separately: any infrastructure change goes only through code, manual edits in the console are prohibited and are caught by state comparison. This is what keeps the metrics holding months after implementation, not just in the first month.

How is Pulumi different from other tools?

The key difference of Pulumi is that infrastructure is described in an ordinary programming language, not in a domain-specific declarative DSL.

This is not cosmetic: loops, functions, typing, modules, code reuse, and full-fledged testing of the configuration with the same tools as the application all become available.

When infrastructure is code in a language the team already knows, the barrier to entry drops, and change review follows the usual process.

Let's compare with declarative approaches.

Tools based on HCL and YAML handle typical scenarios well and read almost like documentation, but as soon as logic is needed — conditional resource generation, computations, reusable abstractions — you have to resort to workarounds: templates, generators, external scripts.

Pulumi solves this directly: the same code creates resources, validates input data, and deploys environments based on parameters.

Manual management via scripts and the console deserves separate mention. Scripts do not store state, do not track configuration drift, and cannot roll back predictably — when a failure occurs, no one knows what is actually deployed.

Pulumi maintains state, shows a plan of changes before applying, and performs a rollback to the previous state. This is the difference between "it works as long as no one touched it" and a reproducible result.

The choice of approach depends on the task. For simple static infrastructure, a declarative DSL remains a reasonable minimum.

When there are dozens of resources, several environments, and the team writes application code, the programmable approach pays off: less duplication, higher speed of changes, lower risk of manual errors. We analyze your case and propose an approach based on facts, not habit.

Common technical concerns

Pulumi stores infrastructure state in a backend — by default this is a managed service, but it can be switched to your own object storage with encryption and locking of concurrent runs.

Secrets are not stored in plaintext in the code: they are marked as encrypted and are only decrypted at the moment of applying. Access is granted through roles, and the change history shows who changed each resource and when.

Compatibility with existing infrastructure is handled through import: resources created manually or by another tool are described in code and connected to the state without being recreated.

After that, changes go through a preview — you see the exact list of what will be created, changed, or deleted before applying.

How does migration from manual management or another tool work?

We inventory the resources, describe them in code, and import them into the state one by one, verifying the result after each step. In parallel, we set up preview in the checks so that discrepancies are caught before applying. The infrastructure keeps running — the switchover happens without downtime.

Can an unsuccessful change be rolled back?

Yes. The state is versioned, so returning to a previous point means reapplying the saved configuration. For critical environments, we set up a mandatory preview and confirmation, and we mark destructive operations with protection against accidental deletion.

What about support after launch?

We leave behind the described infrastructure, access policies, and instructions for typical operations. After that, we provide ongoing support: we update providers, resolve discrepancies between the code and the actual state, and add new environments. Changes go through the same checks as during implementation.

Let's discuss your task

The conversation starts with your infrastructure, not with a template proposal.

It's important for us to understand what is already described by code and what lives by hand: how many environments there are, how access roles are structured, and where states currently diverge between stands.

The answers show whether a targeted Pulumi setup on top of the existing contour is needed or whether part of the resources should be moved away from manual management.

Next, we come back with a project estimate and a work plan: which stacks and providers we connect, how we organize state and secret storage, and which checks we put in place before applying changes.

The plan is broken into stages with a clear result at each one — you see what will appear in your contour and in what order.

What you get as a result:

  • A description of the current state of the infrastructure and the points where manual edits create risk.
  • A scheme for splitting into stacks and environments with justification for the boundaries.
  • Provider configurations, state backend, and access policies.
  • A procedure for migrating existing resources without service downtime.
  • A set of checks before applying changes and rollback rules.
  • A regulation for how the team works with infrastructure code and reviews edits.
  • An estimate of timelines and scope of work by stage.

Describe the task in free form: what services there are, how many environments, who currently makes changes, and which failures keep recurring. That is enough to come back with an estimate and a plan — with no obligations on your side.

Our competencies:

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1393
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1368
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1139
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1152
  • Website development for SBH Partners
    Website development for SBH Partners
    1231
  • Website development for Red Pear
    Website development for Red Pear
    641