Learn how to write constraints and non-goals in app specs so rework drops fast. Use a simple format for fixed stack, budget, deadline, and what can change.

Rework is what happens when you build something that works, but it’s the wrong thing for the project. Teams redo screens, rewrite logic, migrate data, or rebuild a feature because a key decision shows up late.
It often shows up in familiar ways: a flow gets rebuilt because the wrong user roles were assumed; screens get redesigned because mobile support was expected but never stated; the data model changes because “we need audit history” appears after version one; an integration gets swapped because a client can’t use a third-party service; or the app has to move hosting because of compliance or region rules.
Missing constraints create surprise decisions later. When a spec says “build a CRM,” it leaves dozens of questions open: who uses it, what platforms matter, what security rules apply, what must stay out of scope, what budget and timeline are real. If the answers arrive after code exists, the project pays twice: once to build, and again to undo.
A simple example: a founder asks for “appointments + reminders.” Week one ships email reminders. Week two they mention they need SMS, but SMS isn’t allowed in their country or it breaks the budget. Now the reminder system gets redesigned, screens change, and testing restarts. The rework wasn’t caused by bad coding. It was caused by late constraints.
The goal is to reduce back-and-forth before any code is written or generated. Whether you code by hand or use a chat-based builder, the output can only follow the rules you give it. If the rules show up late, the work shifts and you redo it.
This isn’t about writing a long document. A lightweight spec can still be strict where it matters. Early on, it should answer:
When constraints and non-goals are written first, they act like guardrails. You get fewer surprises, fewer rebuilds, and clearer decisions from day one.
Constraints are fixed decisions your project has to live with. Ignore them and you do work twice, because you build in a direction that can’t ship.
Non-goals are explicit choices not to build something. Skip them and the spec quietly grows as people add “small” extras. That’s how you end up redoing screens, flows, and data models.
A quick rule: constraints limit how you build; non-goals limit what you build.
A constraint is a must that doesn’t change without a real decision (and a trade-off).
Examples:
When a constraint is real, write it as a sentence you can’t argue with. If someone says “maybe,” it isn’t a constraint yet.
A non-goal is an explicit “we are not doing this,” even if it sounds useful. It protects the first release.
Examples:
Non-goals aren’t negativity. They prevent expensive detours. For example, “no custom roles in v1” can save weeks of permission edge cases that force a database and UI redesign.
Before you write pages of details, write one sentence that pins the project to the wall. It keeps everyone aligned when trade-offs show up.
A good one-liner answers: who is this for, and what main job should it do?
Example one-liners:
Then add a small success definition: 3 to 5 outcomes a real user should achieve when the project is done. Write them as user results, not features.
For the tutor booking example:
If you don’t have metrics yet, describe success in words. “Fast” is vague, but “feels quick on a phone” is still useful. “Easy” is vague, but “no setup call needed” is clearer. You can add numbers later.
Keep this section short. It becomes the context for everything that follows: what must be true, what must not happen, and what can change.
Rework often starts when the schedule and decision process live only in someone’s head. Put the project constraints in the spec before you describe screens and features.
Write them as plain, testable statements:
A simple example:
“First release must ship by May 30. It includes login, a basic customer list, and one monthly report. No integrations in v1. Budget is capped at $8,000 including hosting for the first month. Reviews happen within 24 hours on weekdays. Product owner is Sam, who approves scope changes.”
Feedback speed deserves its own line because it controls how safely you can move. If stakeholders can only review once a week, the spec should favor smaller releases and fewer edge cases.
Pick a review cadence that matches reality: same-day feedback, 24 to 48 hours on weekdays, weekly review meeting only, or (rarely) “no feedback needed.”
If you don’t write technical constraints early, people fill the gaps with assumptions. That’s how teams end up redoing screens, migrations, or integrations after work has already started.
Start by stating what is locked and what is only a preference. “Prefer React” is not the same as “must be React because we rely on an in-house component library.” One sentence per decision is enough.
Be explicit across the whole app: web, backend, database, and mobile. If a part is flexible, say so and add a boundary (for example, “mobile is web-only in v1”).
A simple way to write it:
Then list the integrations you can’t avoid. Name the systems (payments, email, analytics, CRM) and note hard limits. Examples: “Must use Stripe for billing,” “Must send email via our existing provider,” “Analytics must not track personal data.” If authentication is fixed (SSO, Google login, passwordless), state it.
Hosting choices change architecture. Write where the app must run and why: “Must run in Germany,” “Data must stay in the EU,” or “Can run globally.”
If you have compliance needs, keep them concrete: retention period, deletion rules, and audit needs.
Example: “Store records for 7 years, delete within 30 days of a verified request, keep an audit log of who viewed a record, and deploy only in the country where patients live.” These lines prevent late surprises right when you’re ready to ship.
Non-goals are the guardrails of a spec. They say what you’re not building, not supporting, or not trying to perfect in the first release. This is one of the fastest ways to reduce surprises, because many “small” requests arrive later and quietly change the whole plan.
A good non-goal is specific enough that a teammate can spot scope creep in one sentence. It should also be time-bound. “Not in v1” is clearer than “we won’t do this.”
Start with features people commonly assume are included. For a simple booking app, that might look like:
These aren’t bad features. They’re expensive features. Writing them down keeps the first release focused.
Also call out “detail” items that cause major knock-on work: roles, permissions, and edge-case workflows. “No custom roles. Only two roles: Owner and Member.” That one line can save weeks.
Teams often forget non-goals that aren’t features. They show up later as painful rework.
Decide what you will not optimize for. For example: “We will not tune for 1M users. We assume up to 500 weekly active users in v1.”
Also note what you will not support, so testing stays realistic: “No Internet Explorer,” “No tablet-specific layouts,” or “Login only via email and password (no SSO, no magic links).”
A spec feels safer when it allows small decisions to evolve. If you only write what’s fixed, every new idea turns into a debate. A short “can change” list gives people room to improve the product without restarting the whole plan.
Keep it practical. Cover what you expect to learn after you see a working version, not major new features. Common flexible items include UI text, small flow tweaks, reporting columns, naming (roles, statuses, categories), and basic layout choices.
Next, decide how changes get accepted. Without a simple approval rule, “quick tweaks” turn into quiet scope creep.
A simple workflow that works for most small teams:
The key rule: flexible changes must not break fixed constraints. If your stack is React + Go + PostgreSQL, a “can change” request can’t become “let’s switch the backend.” If the deadline is fixed, “can change” can’t mean adding a new module that needs two more weeks.
Add one trade-off note everyone agrees to. Example: “If we add a new user role with custom permissions, we delay advanced reporting to phase 2.”
A good spec starts by limiting options, not expanding them. This format forces you to write the rules before anyone starts building.
Use this as a header in your doc:
SPEC v0.1 (date)
Owner:
Reviewers:
1) One-liner
- Build: [what it is]
- For: [who]
- So they can: [main benefit]
2) Success definition (3 outcomes)
- Outcome 1: [measurable result]
- Outcome 2: [measurable result]
- Outcome 3: [measurable result]
3) Fixed constraints (cannot change without re-approval)
- Deadline: [date]
- Budget: [$ or hours]
- People: [who is available]
- Tech stack: [fixed choices]
- Hosting/region: [where it must run]
4) Non-goals (must NOT happen)
- [explicit “no”]
- [explicit “not in v1”]
- [explicit “we won’t support”]
5) Open questions
- Q: [question]
Owner: [name]
Due: [date]
6) Lock rule
- After review: changes require: [what approval looks like]
Most surprises aren’t bad luck. They happen because the spec leaves room for different interpretations.
One common trap is mixing goals and solutions. Teams jump straight to screens and workflows before writing down what’s fixed (deadline, budget, tech stack) and what’s out of scope. The result is a pretty UI plan that can’t fit the constraints.
Another trap is vague non-goals. “No extra features” sounds strict, but it doesn’t protect you when someone asks for “just one more report” or “a quick admin panel.” Good non-goals are specific and testable.
Hidden budget or a “soft” deadline is also a scope bomb. If the real budget is $5k and the spec reads like a $50k product, the team will build the wrong thing. Put the uncomfortable numbers on the page.
Integrations and data ownership cause quiet surprises too. If you say “connect to Stripe” but don’t define which events, which fields, and who owns the data, you’ll revisit the same decisions repeatedly.
A final trap is changing constraints mid-build without naming the trade-off. Switching from “web only” to “web plus mobile,” or from “use Postgres” to “use whatever is cheapest,” changes the plan. You can change it, but you must update scope, timeline, or quality expectations.
Add a short note in your spec that answers five points:
Before anyone starts building, you should be able to answer the “what’s fixed?” questions without digging through a long document.
Fast check:
If one of these is missing, the first build will still happen, but the second build will be the real one.
Next steps that keep momentum without locking you into bad decisions:
If you’re using Koder.ai (koder.ai), “Planning Mode” plus a clear constraints and non-goals section helps the platform generate a first draft that matches your stack, hosting region, and scope. And if priorities shift, snapshots and rollback let you test changes without losing a stable baseline.
When these rules are written down early, feature discussions get easier because everyone knows what must stay fixed and what’s allowed to move.
Rework is when you build something that functions, but it can’t ship because a late decision changes the rules. It usually happens when specs don’t state key constraints early, so the team makes reasonable assumptions that later turn out to be wrong.
Start with what cannot change without a real trade-off, like deadline, budget cap, hosting region, required stack, and compliance rules. Then add a short non-goals section so people don’t silently expand scope with “small” extras.
A constraint limits how you build, such as “must run in the EU” or “must use React and PostgreSQL.” A non-goal limits what you build, such as “no mobile app in v1” or “no custom roles at launch.”
Write it as a sentence that can be tested, not a preference. If someone can say “maybe” and nobody can enforce it, it’s not a real constraint yet and you should treat it as an open question.
Pick 3 to 5 user outcomes that describe what success looks like for the first release, in plain language. Outcomes keep the team focused on what users must accomplish, which makes it easier to say no to features that don’t serve the first release.
Common ones are mobile support, roles and permissions, audit history, data residency, and integrations that a client can’t use. If you surface those early, you avoid redesigning screens, changing the data model, or swapping providers late in the project.
Be specific and time-bound, like “not in v1” or “we will not support tablets.” A vague non-goal like “no extra features” won’t stop scope creep because it doesn’t clearly block any specific request.
Write down who approves changes, how fast reviews happen, and what cadence you’ll use to evaluate requests. Slow feedback is a real constraint because it affects how safely you can iterate and how much uncertainty you can handle.
List them as open questions with a single owner and a due date, and don’t start building the affected area until the answer is locked. If you must start, explicitly note the assumption you’re using so it can be revisited without confusion.
Use planning to lock constraints and non-goals before generating anything, so the first draft matches your stack, region, and scope. If priorities shift, features like snapshots and rollback help you test changes without losing a stable baseline, and source code export helps if you need to move work elsewhere later.