Standing Up a SaaS Company

Turning a product idea into a real company that can transact

6/29/20267 min read
Two people planning a business at a desk with laptops and a hand-drawn roadmap

Writing the software was the easy part#

I've spent most of my career building software for other people. When I decided to build my own SaaS product, I assumed the hard part would be the code. I was wrong. The code is the part I know how to do. The part I underestimated was everything around the code: forming a company, getting an EIN, opening a bank account, wiring up cloud accounts under the right identity, publishing legal pages, and getting the thing deployed safely behind an invite gate.

What surprised me most was how much of it is a dependency graph, not a checklist. You can't get an EIN until the entity exists. You can't open a business bank account without the EIN and the formation document. Stripe won't verify you without the bank account. Half my early frustration came from trying to do things in the wrong order and hitting a wall because some earlier step wasn't done yet.

This is what I learned working through it.

⚠️ One disclaimer up front: none of this is legal or tax advice. Entity formation, operating agreements, and tax elections have real consequences. I had the non-boilerplate parts reviewed, and the specific choices below (single-member LLC, Iowa, etc.) are what made sense for my situation, not a recommendation for yours.

The decisions that cascade into everything else#

Before touching a single form, there were a few decisions that shaped every step after them. I made them deliberately and then stopped second-guessing them:

  • Entity type: an LLC. A C-Corp only really pays off if you're raising venture money. For a bootstrapped SaaS, an LLC is the simplest thing that works.
  • Formation state: my home state. Delaware is great if you have outside investors; otherwise it's a second filing plus foreign-registration overhead for no real benefit.
  • Member structure: single-member, which is a "disregarded entity" for federal tax by default.
  • Registered agent and business address: a commercial registered agent and a virtual office, specifically to keep my home address off the public record.
  • Cloud: AWS, because that's what my infrastructure is built on.

One small habit paid off more than I expected: I kept a single source of truth for the details that everything keeps asking for — the exact legal name, the domain, the various role emails, the EIN, the AWS account id, the Stripe account id. Having one place where "the company's legal name is exactly this" lives saved me from a dozen small inconsistencies later.

This is the part that taught me the dependency lesson the hard way. The order is rigid:

name check → registered agent + address → file formation → EIN → operating agreement → bank account → insurance.

A few things stood out doing it for real:

Verify the name everywhere before you commit. I searched the Secretary of State business database, searched USPTO for trademark conflicts on the brand, and confirmed the matching domain was available, all before falling in love with a name. Getting any one of those wrong after the fact is expensive.

Privacy is a decision you make at filing time, and it's public forever. The formation filing is a public document. I used my virtual office address for the principal office and the commercial registered agent for the agent article, not my home address. This is one of those things you can't quietly undo later.

Get the EIN directly from the IRS. It's free at irs.gov and takes about fifteen minutes. Plenty of third parties will happily charge you for it. Don't pay them. The EIN also means I'm not handing my SSN to every vendor.

The operating agreement has to stay consistent with the certificate. Even as a single-member LLC where it's not strictly required by law, the operating agreement is what establishes the LLC as a distinct entity, which matters for liability protection. The two parts that are actually specific to your business are the purpose clause and the capital contribution amount, and the contribution has to match what you actually deposited in the bank. Name, address, agent, and management style all have to match the certificate exactly.

Then the bank, then insurance. The bank needed the EIN, the formation doc, and the operating agreement together. Once that was open, I provisioned a card for the recurring SaaS and cloud bills so nothing personal ever touches the business. Insurance (general liability, professional/E&O, and cyber) was the last legal step.

At the end of all this I had something I didn't have before: a real company that can actually transact.

Identity and cloud accounts#

The theme here is identity discipline. The single most important rule I followed: the cloud accounts get created under a Workspace admin email on the company domain, never my personal Gmail. Untangling that later is a nightmare.

This had its own rigid order: domain → Google Workspace → email and DNS → AWS account → IAM/SSO users → Terraform Cloud → Stripe. A few things I learned along the way:

  • Email deliverability is not optional. Without SPF, DKIM, and DMARC set up properly, my transactional email — verification, magic links, alerts — would land in spam. I set DMARC to p=none to start and will tighten it to quarantine once the mail stream is clean.
  • Lock down the AWS root user immediately. Hardware/app MFA, no access keys on root, a billing alarm and budget, and then I created a proper admin user so I never log in as root for daily work. The CI/CD pipeline deploys via a GitHub OIDC role, so there are no long-lived AWS keys sitting in GitHub.
  • Stripe gets verified pre-launch. Even before opening to users, I completed business verification with the EIN, formation doc, and bank account so billing is ready the day I flip the switch.

Web presence and making the app safe to expose#

With the domain and email live, the marketing pieces could run in parallel — LinkedIn and Facebook pages, GA4, Search Console, and a coming-soon page with email capture so I'm building a launch list while the product is still gated.

Making the app itself safe to expose was mostly configuration and content rather than new building, because my stack already implements the patterns:

  • Invite-only signups. There is deliberately no public registration endpoint. An admin invites by email, the invitee gets a reset token or signs in with OAuth on the same email. Every CTA points at "request access," not "sign up."
  • Bot protection via reCAPTCHA on the auth-adjacent endpoints, with the secret plumbed through Secrets Manager.
  • Terms of Use and Privacy Policy published and version-tracked, with the processor list (AWS, Stripe, Google, analytics) actually matching reality.
  • Deploy and verify. Populate every production secret, terraform apply the prod environment, let CI roll out the app, run migrations, seed the initial admin, and smoke-test login, the invite flow, a Stripe test charge, and reCAPTCHA.

The payoff at the end of this is the live product behind the invite gate — the first time the whole thing feels real.

What I'd tell myself at the start#

Three things would have saved me time:

  1. Respect the order. Almost every "I'm blocked" moment was me trying to do a step before its prerequisites existed. The dependency graph isn't bureaucracy; it's physics.
  2. Make the privacy and identity decisions early and on purpose. The address on a public filing and the email a cloud account is rooted to are both painful to change after the fact.
  3. Keep one running record of what you decided and why. The details that everything downstream depends on are easy to get subtly inconsistent, and a single source of truth is cheap insurance.

Building the software is still my favorite part. But the company around it is what turns a side project into something that can actually take a customer's money — and that turned out to be a craft of its own.