Category: Engineering

  • Engineering Impact: Inside the Tech Stack that Powers the Trillion Tree Campaign

    Engineering Impact: Inside the Tech Stack that Powers the Trillion Tree Campaign

    When we talk about climate change, we usually talk about carbon, temperature, and policy. But at Plant-for-the-Planet, we also talk about scale.

    The Trillion Tree Campaign isn’t just a slogan; it’s a logistical beast. How do you track planting data from 225+ projects globally? How do you visualize geospatial data for millions of trees without crashing a mobile browser? And how do you process donations from Apple Pay, Google Pay, and Stripe while ensuring every cent is traceable?

    I spent a significant part of my career architecting solutions for these problems. While my previous post covered the why, this post covers the how.

    Here is a technical deep dive into the development of Forest Cloud, the open-source platform driving the global reforestation movement.

    The Core Stack: Performance Meets Purpose

    The platform (web.plant-for-the-planet.org) needed to be fast, SEO-friendly (so projects get found), and capable of handling complex state management.

    • Frontend: We utilized Next.js (React) for its hybrid static/server-side rendering capabilities. This was crucial for indexing the individual pages of hundreds of planting projects.
    • Widgets: For embeddable components (like the tree counter you might see on partner sites), we used Svelte. Its compile-step approach meant we could ship tiny, highly performant bundles that didn’t drag down the host websites.
    • Backend: We leaned heavily into Serverless APIs. When traffic spikes during a climate awareness campaign, serverless functions scale instantly. We implemented aggressive caching strategies to ensure that the “Tree Counter” didn’t hammer our database on every page load.

    Challenge 1: Visualizing the Invisible

    One of my biggest tasks was making the data “real” for donors. A number on a screen is abstract; a satellite image of a restoration site is tangible.

    We developed interactive maps using Mapbox GL JS and ESRI. The challenge here wasn’t just rendering a map; it was rendering heavy geospatial tree planting data alongside satellite imagery layers without killing performance.

    By optimizing how we loaded vector tiles and managing state carefully, we created a seamless experience where users could zoom from a global view down to specific planting sites in the Yucatan. This accessibility directly correlated with impact: in 2021 alone, we saw a 378% increase in trees planted.

    Challenge 2: DevOps & The “n8n on Heroku” Story

    Automation is the silent hero of non-profits. We used n8n (a workflow automation tool) to glue various services together. However, deploying it cost-effectively was a hurdle.

    I created the first-ever Docker implementation of n8n specifically for Heroku deployment. This allowed us to run complex workflows—like triggering emails or syncing data between CRMs—without managing a dedicated server. It was a perfect example of how “devops creativity” can save resources that are better spent on planting trees.

    The Pipeline:

    • CI/CD: We moved to a strict version-controlled environment. I managed pipelines on Heroku, Vercel, and Gridpane, ensuring that code moved from develop to staging to production via automated GitHub Actions.
    • WordPress as Headless: We didn’t abandon WordPress; we just used it better. I wrote custom PHP plugins to expose WordPress content via REST APIs, effectively treating it as a Headless CMS. This gave the content team a familiar interface while keeping the frontend strictly React-based.

    Challenge 3: Trust & Payments

    The Transparency Standards at Plant-for-the-Planet are rigorous. We couldn’t just “take money”; we had to route it.

    I worked on integrating a multi-gateway payment system including Stripe, PayPal, Apple Pay, and Google Pay. The complexity wasn’t just in the API calls, but in the webhooks—ensuring that when a payment succeeded, the “Tree Counter” updated, the donor got a receipt, and the specific planting project was credited, all in real-time.

    Why This Matters

    Open Source is usually associated with developer tools, but Green Open Source is a growing field. By making our repository public (GitHub Link), we invite developers to audit our code and contribute to climate justice.

    This project wasn’t just about writing code; it was about building the digital soil in which a trillion trees could take root.


    If you are interested in how we used Docker to containerize automation tools or want to discuss the geospatial challenges of mapping a trillion trees, feel free to reach out.

  • Deploying the Undeployable: How I Engineered the First Dockerized n8n for Heroku

    Deploying the Undeployable: How I Engineered the First Dockerized n8n for Heroku

    When I set out to automate Plant-for-the-Planet’s internal workflows, I had a simple requirement: I needed n8n (a powerful workflow automation tool), but I didn’t want to manage a server.

    We were already using Heroku for our main stack, so deploying n8n there seemed like the logical step. I thought it would be a quick afternoon task: write a Dockerfile, push it, and go home.

    I was wrong. What followed was a week of relentless trial and error, staring at CrashLoopBackOff logs, and hacking around Heroku’s strict security model.

    Here is the story of how I built the first stable, one-click Docker deployment for n8n on Heroku—and the specific technical hurdles I had to break to get there.

    Phase 1: The “Permissions” Hell

    The first wall I hit was immediate. I tried deploying the standard n8n Docker image, and the app crashed instantly.

    The logs were cryptic but pointing to a permissions failure:

    Bash

    su-exec: setgroups: Operation not permitted
    [WARN tini (3)] Tini is not running as PID 1
    

    The Engineering Conflict:

    The official n8n image at the time relied on su-exec to switch users at runtime. It expected to start as root, set up permissions, and then drop down to the node user.

    Heroku, however, is a locked-down PaaS. It runs containers with a random, non-root user ID for security. It strictly forbids setgroups calls. Basically, the container was trying to say “I am root,” and Heroku was saying “No, you are not.”

    The Fix:

    I had to rebuild the image from scratch. I wrote a custom Dockerfile that stripped out the su-exec logic entirely. Instead of trying to switch users at runtime, I configured the image to run natively as the node user from the start, ensuring it never requested privileges Heroku wouldn’t grant.

    Phase 2: The Random Port Lottery

    Once I fixed the user permissions, the app started—but nobody could reach it.

    Heroku reported: Error R10 (Boot timeout) -> Web process failed to bind to $PORT.

    The Engineering Conflict:

    n8n defaults to listening on port 5678.

    Heroku doesn’t care about your defaults. It assigns a random port to your application every time the dyno restarts (e.g., 12345, 54321) and passes it via the $PORT environment variable. If your app doesn’t listen on exactly that port within 60 seconds, Heroku kills the process.

    The Fix:

    I couldn’t hardcode the port in a config file because it changed every 24 hours. I had to write a dynamic entrypoint script (docker-entrypoint.sh) to bridge the gap:

    Bash

    #!/bin/sh
    if [ -z ${PORT+x} ]; then
        echo "PORT variable not defined, leaving N8N to default port."
    else
        # Inject Heroku's random port into n8n's expected variable
        export N8N_PORT=$PORT
        echo "N8N will start on '$PORT'"
    fi
    
    # Execute the command
    n8n start
    

    This script acts as the translator between Heroku’s infrastructure and n8n’s runtime.

    Phase 3: The “Deploy to Heroku” Button

    Fixing the code was only half the battle. I wanted this to be reusable for my team (and others). I didn’t want anyone else to have to manually configure Heroku Postgres or Redis just to get this running.

    I introduced an app.json manifest to the repository. This file tells Heroku exactly what the app needs before it even builds:

    JSON

    "env": {
        "DB_TYPE": {
            "description": "The type of database to use.",
            "value": "postgresdb"
        },
        "N8N_ENCRYPTION_KEY": {
            "description": "The encryption key for n8n.",
            "generator": "secret"
        }
    },
    "addons": [
        "heroku-postgresql",
        "heroku-redis"
    ]
    

    By defining the addons and environment generation in code, I turned a complex manual deployment into a literal “One-Click” install.

    The Result

    After dozens of commits (you can scroll through the initial commit history to see the struggle), I finally had a stable architecture.

    This solution allowed Plant-for-the-Planet to run critical automation pipelines on a zero-maintenance infrastructure. But beyond our use case, it took on a life of its own. The repository sarveshpro/n8n-heroku has since been starred and forked hundreds of times by other developers facing the exact same constraints.

    Open source isn’t always about inventing a new framework. Sometimes, it’s just about banging your head against a wall until you find the door—and then holding that door open for everyone else.


    If you need to deploy n8n on Heroku today, you don’t need to repeat my trial and error. You can just fork the solution here:

    GitHub – sarveshpro/n8n-heroku