<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ruben Marcus</title>
    <description>The latest articles on DEV Community by Ruben Marcus (@rubenmarcus).</description>
    <link>https://dev.to/rubenmarcus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F625692%2F9d8d8bf9-16b7-4b3d-b395-f28427e31e2a.jpeg</url>
      <title>DEV Community: Ruben Marcus</title>
      <link>https://dev.to/rubenmarcus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rubenmarcus"/>
    <language>en</language>
    <item>
      <title>Automating entire workflows with ralph-starter</title>
      <dc:creator>Ruben Marcus</dc:creator>
      <pubDate>Thu, 19 Feb 2026 00:52:59 +0000</pubDate>
      <link>https://dev.to/rubenmarcus/automating-entire-workflows-with-ralph-starter-43gc</link>
      <guid>https://dev.to/rubenmarcus/automating-entire-workflows-with-ralph-starter-43gc</guid>
      <description>&lt;h2&gt;
  
  
  What is ralph-starter
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/multivmlabs/ralph-starter" rel="noopener noreferrer"&gt;ralph-starter&lt;/a&gt; is a CLI tool that orchestrates AI coding agents in autonomous loops. You give it a task (or point it at a GitHub issue, a Linear ticket, a Notion page), it runs the agent, checks if tests pass, if lint is clean, if build works. If something fails it feeds the error back to the agent and loops again. When everything passes it commits, pushes, and opens a PR.&lt;/p&gt;

&lt;p&gt;It supports Claude Code, Cursor, Codex CLI, OpenCode, Gemini CLI, Copilot, Amp, and Openclaw. You do not need to pick one in advance, it auto-detects what you have installed.&lt;/p&gt;

&lt;p&gt;It is open source, MIT licensed. I built it because I was tired of being the middleman between my terminal and my AI chat window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I was using AI coding assistants every day. Claude, ChatGPT, Copilot, whatever was available. And the workflow was always the same: I read a ticket, I open the editor, I start coding, I get stuck, I open the AI chat, I paste the context, I get a suggestion, I adapt it, I paste it back. Then I run tests. Something breaks. I go back to the chat, paste the error, get a fix, paste that back. Lint complains. Another round trip. Then I commit, push, open a PR.&lt;/p&gt;

&lt;p&gt;That is like 12 steps and I was doing it 5 to 8 times a day. The AI was doing the hard part (writing the code) and I was just the relay moving text between windows. I felt like a human clipboard.&lt;/p&gt;

&lt;p&gt;So I wrote a script that does the relay for me. The script takes a spec, sends it to the agent, runs my test suite, and if something fails it sends the error output back to the agent automatically. No copying, no pasting, no switching windows. The agent sees the error and fixes it on its own.&lt;/p&gt;

&lt;p&gt;That script grew into ralph-starter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it is most useful
&lt;/h2&gt;

&lt;p&gt;ralph-starter works best when you have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A clear spec.&lt;/strong&gt; "Add /health endpoint that returns 200 with JSON body &lt;code&gt;{ status: 'ok' }&lt;/code&gt;" finishes in 1 loop. "Make the app better" will still run — the agent will analyze your codebase and pick something to improve — but it might take 4 loops and the result might not be what you wanted. The more specific the spec, the fewer loops and the better the output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests.&lt;/strong&gt; The loop needs something to validate against. If you have no tests the agent does not know when it is done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routine implementation work.&lt;/strong&gt; Endpoints, bug fixes, component updates, adding tests, config changes. The stuff that fills up a sprint backlog.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Vague specs do not break it, they just cost more. "Refactor the auth system" with no details will make the agent try different approaches each loop until the circuit breaker trips. "Add JWT middleware at src/middleware/auth.ts using bcrypt, httpOnly cookies, add tests for login success and failure" finishes in 2 loops because the agent knows exactly what done looks like.&lt;/p&gt;

&lt;p&gt;I use it every day for the mechanical parts of development. I still do the thinking, the architecture, the spec writing. ralph-starter handles the translation from spec to code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;You can start from an idea and ralph-starter will generate the spec for you:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fead0j2uzung6rfeybl55.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fead0j2uzung6rfeybl55.png" alt="Getting Started" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you can point it at an existing GitHub issue or Linear ticket and it fetches the spec automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install and initialize&lt;/span&gt;
npx ralph-starter init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ralph-starter init&lt;/code&gt; detects your project type (Node.js, Python, Rust, Go), finds which agents you have installed, and sets up your validation commands (test, lint, build). If it finds a Ralph Playbook in your project it picks up AGENTS.md, IMPLEMENTATION_PLAN.md, and your prompt files automatically:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8k3mcx3537el9afyendf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8k3mcx3537el9afyendf.png" alt="ralph-starter terminal" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run your first task with an inline spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ralph-starter run &lt;span class="s2"&gt;"add a /ping endpoint that returns pong"&lt;/span&gt; &lt;span class="nt"&gt;--commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or point it at a GitHub issue or Linear ticket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From GitHub&lt;/span&gt;
ralph-starter run &lt;span class="nt"&gt;--from&lt;/span&gt; github &lt;span class="nt"&gt;--project&lt;/span&gt; rubenmarcus/ralph-starter &lt;span class="nt"&gt;--issue&lt;/span&gt; 2

&lt;span class="c"&gt;# From Linear&lt;/span&gt;
ralph-starter run &lt;span class="nt"&gt;--from&lt;/span&gt; linear &lt;span class="nt"&gt;--project&lt;/span&gt; ENG &lt;span class="nt"&gt;--issue&lt;/span&gt; ENG-71 &lt;span class="nt"&gt;--commit&lt;/span&gt; &lt;span class="nt"&gt;--pr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4a0e5xnan1d1b17ky3n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx4a0e5xnan1d1b17ky3n.png" alt="ralph-starter terminal" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To connect GitHub, Linear, Notion, or Figma as spec sources, use the config commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ralph-starter config &lt;span class="nb"&gt;set &lt;/span&gt;github.token ghp_xxx
ralph-starter config &lt;span class="nb"&gt;set &lt;/span&gt;linear.apiKey lin_api_xxx
ralph-starter config &lt;span class="nb"&gt;set &lt;/span&gt;notion.apiKey ntn_xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ralph-starter setup&lt;/code&gt; configures the CLI agent preferences. Integrations are managed through &lt;code&gt;ralph-starter config&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the loop works
&lt;/h2&gt;

&lt;p&gt;The loop executor follows this sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Fetch spec (GitHub issue, Linear ticket, inline text)
2. Create branch (auto/42-health-endpoint)
3. Run agent with the spec as prompt
4. Run validations: test → lint → build
5. If any validation fails → feed error output back to agent → go to step 3
6. If all pass → commit, push, open PR
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The validation step is configurable in &lt;code&gt;ralph-starter.config.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;validation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pnpm test&lt;/span&gt;
  &lt;span class="na"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pnpm lint&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pnpm build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a validation fails, ralph-starter takes the stderr/stdout and builds context for the next iteration. The context includes the original spec, the diff of what changed, and the full validation output. The agent sees &lt;code&gt;TypeError: Cannot read property 'id' of undefined at src/routes/user.ts:42&lt;/code&gt; and knows exactly what to fix.&lt;/p&gt;

&lt;p&gt;The agent does not get a summary. It gets the raw error. This is faster than me copying the error into a chat window because there is zero delay between failure and the next attempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real example: building a landing page from a GitHub issue
&lt;/h2&gt;

&lt;p&gt;Here is a real run. I pointed ralph-starter at a GitHub issue that asked for a landing page for a London pet shop. The spec had 8 tasks (header, hero, services, gallery, testimonials, contact form, footer, polish).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3dicjcio7ym0qfrvh78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq3dicjcio7ym0qfrvh78.png" alt="ralph-starter terminal" width="800" height="1188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ralph-starter detected 28 installed skills (frontend-design, tailwind, responsive-web-design, etc.), picked the relevant ones for the task, and started the loop with Claude Code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbwp2f2guebyrsywzazc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbwp2f2guebyrsywzazc0.png" alt="ralph-starter terminal" width="800" height="833"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The loop ran for 2 iterations. First iteration completed 5 out of 8 tasks (Project Setup, Header &amp;amp; Navigation, Hero Section, Services Section, Featured Pets Gallery). Second iteration picked up the remaining tasks (Testimonials, Contact Form, Footer, Polish). It stopped automatically when no file changes were detected for 2 consecutive iterations.&lt;/p&gt;

&lt;p&gt;Final result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cost Summary:
  Tokens: 47.0K (764 in / 46.2K out)
  Cost: $0.606 ($0.348/iteration avg)

Loop completed!
  Exit reason: completed
  Iterations: 2
  Total duration: 8m 19s
  Total cost: $0.696 (47.0K tokens)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;8 minutes. 69 cents. A full landing page with React components, Tailwind styling, and responsive layout. I did not open the editor at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token costs and how to keep them low
&lt;/h2&gt;

&lt;p&gt;This is something people always ask me about. Here are my real numbers.&lt;/p&gt;

&lt;p&gt;I tracked my entire January. 187 tasks completed. $22.41 total. Average of &lt;strong&gt;$0.12 per task&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The reason it is cheap is prompt caching. When using Claude Code, the first loop sends the full context at $3.00 per million input tokens. But loops 2, 3, 4 reuse the cached tokens at $0.30 per million. That is 90% less.&lt;/p&gt;

&lt;p&gt;Before each run, ralph-starter shows you an estimate so you know what to expect:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fij14c51g2co4dp4g13c4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fij14c51g2co4dp4g13c4.png" alt="ralph-starter terminal" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After each run it shows the actual cost breakdown: tokens in, tokens out, cache hits, cost per iteration. No surprises. You always know what you are spending.&lt;/p&gt;

&lt;p&gt;Most tasks finish in 2 to 3 loops. After the first loop, most of the input is already cached. I wrote the detailed breakdown with exact numbers &lt;a href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few things that help keep costs down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Good specs&lt;/strong&gt; mean fewer loops. Clear acceptance criteria = agent knows when it is done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt caching&lt;/strong&gt; saves 90% on input tokens after the first loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit breaker&lt;/strong&gt; stops tasks that are stuck, so you do not burn money on something unsolvable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt; teach the agent patterns so it gets things right faster (fewer iterations = less cost).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Batch mode: 10 issues, 8 PRs
&lt;/h2&gt;

&lt;p&gt;During sprint grooming I label issues as "auto-ready". These are the well defined tickets with clear specs. Then I run a single command and go get lunch:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtrqvmw3aeklyovjvrzy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtrqvmw3aeklyovjvrzy.png" alt="ralph-starter terminal" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ralph-starter picks up all matching issues, shows the estimate for each, and starts the Ralph Wiggum loop one by one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From GitHub&lt;/span&gt;
ralph-starter auto &lt;span class="nt"&gt;--source&lt;/span&gt; github &lt;span class="nt"&gt;--project&lt;/span&gt; multivmlabs/ralph-starter &lt;span class="nt"&gt;--label&lt;/span&gt; &lt;span class="s2"&gt;"auto-ready"&lt;/span&gt; &lt;span class="nt"&gt;--limit&lt;/span&gt; 10

&lt;span class="c"&gt;# From Linear&lt;/span&gt;
ralph-starter auto &lt;span class="nt"&gt;--source&lt;/span&gt; linear &lt;span class="nt"&gt;--project&lt;/span&gt; ENG &lt;span class="nt"&gt;--label&lt;/span&gt; &lt;span class="s2"&gt;"auto-ready"&lt;/span&gt; &lt;span class="nt"&gt;--limit&lt;/span&gt; 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works with both GitHub Issues and Linear tickets. Each issue gets its own branch, its own loop, its own PR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1/10] Issue #145: Add health check endpoint
  &amp;gt; Branch: auto/145
  &amp;gt; 2 loops &amp;gt; Validation: passed
  &amp;gt; PR #151 created

[2/10] Issue #147: Add rate limit headers
  &amp;gt; Branch: auto/147
  &amp;gt; 1 loop &amp;gt; Validation: passed
  &amp;gt; PR #152 created

[3/10] Issue #150: Improve performance
  &amp;gt; 3 loops &amp;gt; Circuit breaker tripped. Skipping.

...

Completed: 8/10 | Failed: 2/10
Total cost: $1.84
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;8 out of 10. The 2 that failed were vague tickets. One was "Improve performance" with no metrics or targets. The agent tried different optimizations each loop but had nothing to validate against. The circuit breaker tripped after 3 loops.&lt;/p&gt;

&lt;p&gt;The other was a refactoring ticket that referenced a discussion from a team meeting. The agent did not have that context.&lt;/p&gt;

&lt;p&gt;The circuit breaker trips after 3 consecutive identical failures or 5 of the same error type. It prevents burning tokens on something the agent cannot solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking an agent
&lt;/h2&gt;

&lt;p&gt;You can be explicit about which agent to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ralph-starter run &lt;span class="s2"&gt;"your task"&lt;/span&gt; &lt;span class="nt"&gt;--agent&lt;/span&gt; claude-code
ralph-starter run &lt;span class="s2"&gt;"your task"&lt;/span&gt; &lt;span class="nt"&gt;--agent&lt;/span&gt; codex
ralph-starter run &lt;span class="s2"&gt;"your task"&lt;/span&gt; &lt;span class="nt"&gt;--agent&lt;/span&gt; cursor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or let ralph-starter auto-detect. It checks what you have installed and uses the first one it finds.&lt;/p&gt;

&lt;p&gt;I use Claude Code daily because prompt caching makes the loops cheaper and stream-json output lets ralph-starter track progress in real time. But the loop executor and validation pipeline are the same for all agents. I ran the same JWT auth task on &lt;a href="https://ralphstarter.ai/blog/five-ai-coding-agents" rel="noopener noreferrer"&gt;4 different agents&lt;/a&gt; and they all got there, just with different loop counts and costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I keep building it
&lt;/h2&gt;

&lt;p&gt;I did a &lt;a href="https://ralphstarter.ai/blog/ralph-starter-vs-manual" rel="noopener noreferrer"&gt;side-by-side comparison&lt;/a&gt; of 12 tasks from the same sprint. 6 manual, 6 with ralph-starter. Same project, same type of work. The ralph-starter tasks averaged 12 minutes of my attention vs 45 minutes coding manually. Code quality was comparable.&lt;/p&gt;

&lt;p&gt;Now I spend my time on three things: writing clear specs (the input), reviewing PRs (the output), and architecture decisions (the part the AI cannot do). Everything in between, the mechanical translation of spec to code, ralph-starter handles that.&lt;/p&gt;

&lt;p&gt;Every PR it produces passes tests, lint, and build. Every one. When I code manually I sometimes skip tests for small changes. The validation loop does not let the agent skip anything and honestly that discipline is better than what I do on my own.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the name
&lt;/h2&gt;

&lt;p&gt;The name comes from the &lt;a href="https://ghuntley.com/ralph/" rel="noopener noreferrer"&gt;Ralph Wiggum technique&lt;/a&gt;. You give the AI a task and let it keep going until done. No micro-managing. &lt;a href="https://ralphstarter.ai/blog/ralph-wiggum-technique" rel="noopener noreferrer"&gt;Full explanation here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;ralph-starter is open source, MIT licensed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/multivmlabs/ralph-starter" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ralphstarter.ai" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/ralph-starter" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Related posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ralphstarter.ai/blog/ralph-wiggum-technique" rel="noopener noreferrer"&gt;The Ralph Wiggum technique&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ralphstarter.ai/blog/specs-are-the-new-code" rel="noopener noreferrer"&gt;Specs are the new code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ralphstarter.ai/blog/five-ai-coding-agents" rel="noopener noreferrer"&gt;I tried 5 AI coding agents on the same task&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ralphstarter.ai/blog/prompt-caching-saved-me-47-dollars" rel="noopener noreferrer"&gt;Prompt caching saved me $47&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ralphstarter.ai/blog/ralph-starter-vs-manual" rel="noopener noreferrer"&gt;ralph-starter vs doing it manually&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ralphstarter.ai/blog/figma-to-code-one-command" rel="noopener noreferrer"&gt;Figma to code in one command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ralphstarter.ai/blog/ralph-starter-with-linear" rel="noopener noreferrer"&gt;ralph-starter with Linear&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it, open an issue or drop a star. All feedback is welcome.&lt;/p&gt;

</description>
      <category>ralphwiggum</category>
      <category>ai</category>
      <category>automation</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Getting started with Next.js + Strapi: Security first</title>
      <dc:creator>Ruben Marcus</dc:creator>
      <pubDate>Sun, 16 May 2021 15:03:00 +0000</pubDate>
      <link>https://dev.to/rubenmarcus/getting-started-with-next-js-strapi-security-first-3380</link>
      <guid>https://dev.to/rubenmarcus/getting-started-with-next-js-strapi-security-first-3380</guid>
      <description>&lt;h1&gt;
  
  
  Why worry about Security?
&lt;/h1&gt;

&lt;p&gt;Before starting to see about Strapi's Content-Types, before looking at Next.js' file and route structure, it's good to discuss Security.&lt;/p&gt;

&lt;p&gt;A concern that usually is not followed up with due attention in certain teams, and that can cause a very high cost, when a project is put into production.&lt;/p&gt;

&lt;p&gt;This article is another introductory article to the Next.js + Strapi stack, we will also cover TypeScript, Data Fetch, Layouts, CI / CD and Deploy, but first of all we will cover security.&lt;/p&gt;

&lt;p&gt;Below we will discuss, the most common security errors in web applications and how to mitigate or fix them in our Strapi + Next.js application:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;XSS / CRSF:&lt;/strong&gt;&lt;br&gt;
XSS or Cross Site Scripting, is a malicious technique to inject code into our application and circumvent security to hijack data or manipulate a user's session for example. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CRSF&lt;/strong&gt; or Cross-site request forgery, is when someone uses a malicious technique to get through a request either via Postman or browser to reach our database, delete user data for example, steal session data (like credit card , addresses, etc.) among other things.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Click Jacking:&lt;/strong&gt;&lt;br&gt;
Do you know when you open pages that tend to trick the user into typing data and in the end they end up sending that data to people they want to use maliciously? Or that they may have malware or exploits and install them on the user's machine?&lt;/p&gt;
&lt;h2&gt;
  
  
  Common vulnerabilities in Rest APIS:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DOS &amp;amp; DDOS (Denial of Service):&lt;/strong&gt; When a hacker wants to take down an API, application or website, he can fire bulk requests for that API or endpoint.&lt;br&gt;
Exposure of Sensitive Information: When we expose sensitive user data, especially without encryption in our API. Ids, emails, addresses, payment information, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MIM (Man in the Middle) attacks:&lt;/strong&gt; When a hacker tries to intercept client and server communication, with the intention of stealing data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SQL Injection:&lt;/strong&gt; Injection of code that changes the expected behavior of the API and the Database. Through an injection, a hacker is able to steal information, break the API, change its operation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Insecure Direct Object References:&lt;/strong&gt; When you expose an API with endpoints like &lt;code&gt;/ user / id / 30&lt;/code&gt;, and a user tries to access an ID that does not compete with it, and succeeds, you are exposing &lt;br&gt;
Direct References for insecure objects.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Common vulnerabilities in GraphQL APIS :
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;/ graphql? query = {__ schema {types {name, fields {name}}}}:&lt;/strong&gt;&lt;br&gt;
If your GraphQL API is public, only with a query like this, the user who uses it, can see the entire schema of your API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Malicious Queries:&lt;/strong&gt; Hackers can mount malicious queries, whether to steal data, corrupt your database, or bring down your API / server&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Brute-Force:&lt;/strong&gt; To avoid problems with hackers trying to break the data in your GraphQL API, you can use plugins like &lt;a href="https://github.com/teamplanes/graphql-rate-limit" rel="noopener noreferrer"&gt;GraphQL Rate Limit&lt;/a&gt;, which will limit how many times the vulnerable fields of your query can be executed in a time interval.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How to avoid all this?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;On Strapi:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Understanding the Strapi Configuration file &amp;amp; its security:&lt;/strong&gt; Strapi has rich documentation that shows us &lt;a href="https://strapi.io/documentation/3.0.0-beta.x/concepts/configurations.html#security" rel="noopener noreferrer"&gt;how to guarantee the security of the CMS&lt;/a&gt;:&lt;br&gt;
It has configurations for XSS, P3P, Hsts, X-Frame-Options (Clickjacking), CORS (very useful to define which domains can access your application, which headers can be exposed),&lt;br&gt;
IP (Can configure which IPS see or not your application)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Credential Injection:&lt;/strong&gt; Use a .env file, to avoid injecting credentials in the middle of your code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validation:&lt;/strong&gt; You can create a &lt;a href="https://medium.com/@prakash.gangurde/how-to-create-a-middleware-for-strapi-f80a24876fc9" rel="noopener noreferrer"&gt;middleware&lt;/a&gt; to validate that your application data already exists and will not be duplicated, or you can also use a lib like &lt;a href="https://github.com/hapijs/joi" rel="noopener noreferrer"&gt;Joi&lt;/a&gt;, to validate your API fields, but Strapi already has some &lt;a href="https://strapi.io/documentation/v3.x/concepts/models.html#define-the-attributes" rel="noopener noreferrer"&gt;native validations&lt;/a&gt; that you can define in your API models, only if you use MongoDB&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Roles &amp;amp; Permissions:&lt;/strong&gt; Ideally, you should create documentation for your API on which permissions and endpoints you will enable so that you don't end up making the mistake of allowing everything and offering risk to your API data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Policies:&lt;/strong&gt; You can &lt;a href="https://strapi.io/documentation/3.0.0-beta.x/concepts/policies.html#usage" rel="noopener noreferrer"&gt;set your API's policies&lt;/a&gt; directly in Strapi's code through &lt;code&gt;./config/policies&lt;/code&gt; for global Policies and &lt;code&gt;./api/**/config/policies&lt;/code&gt; for local endpoints. It is an extra layer of security for your Strapi application. To set policies with GraphQL, Strapi's documentation has a &lt;a href="https://strapi.io/documentation/3.0.0-beta.x/plugins/graphql.html#customise-the-graphql-schema" rel="noopener noreferrer"&gt;page&lt;/a&gt; dedicated to that.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data-Leak:&lt;/strong&gt; You can pass a private: true parameter, within the parameter in your API model, to remove the value of being accessed by anyone. &lt;a href="https://strapi.io/documentation/v3.x/concepts/models.html#define-the-attributes" rel="noopener noreferrer"&gt;Click here&lt;/a&gt; to learn more&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;JWT:&lt;/strong&gt; you can require the user to access sensitive endpoints of your application to be &lt;a href="https://strapi.io/documentation/v3.x/guides/jwt-validation.html#customize-the-jwt-validation-function" rel="noopener noreferrer"&gt;logged in and use JWT&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exposure of Sensitive Information:&lt;/strong&gt; Strapi allows to &lt;a href="https://strapi.io/documentation/3.0.0-beta.x/guides/custom-data-response.html" rel="noopener noreferrer"&gt;edit the controllers&lt;/a&gt;, which information can be accessed in the calls of the endpoints. You can delete certain fields and parameters from the results.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In GraphQL:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DOS (Denial of Service):&lt;/strong&gt; You need to limit your queries. A malicious hacker, if discovered its GraphQL API, can mount a series of queries that can overload your server. This is a &lt;a href="https://www.apollographql.com/blog/securing-your-graphql-api-from-malicious-queries-16130a324a6b" rel="noopener noreferrer"&gt;great article&lt;/a&gt; on the Apollo blog that teaches some cases of malicious queries and how to avoid them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://strapi.io/documentation/3.0.0-beta.x/plugins/graphql.html#customise-the-graphql-schema" rel="noopener noreferrer"&gt;Setting Policies for Queries:&lt;/a&gt;&lt;/strong&gt; You have to customize the Schema of your GraphQL API, setting the desired policies to have control of who or how to access what in your API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unauthorized access:&lt;/strong&gt; You need to disable the GraphQL Playground, which is already disabled in the production version of Strapi (you can disable it for other environments here), then your GraphQL endpoint is not maintained by a route but by middleware.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is necessary to create a &lt;a href="https://strapi.io/documentation/v3.x/concepts/middlewares.html#middlewares" rel="noopener noreferrer"&gt;new middleware,&lt;/a&gt; which will check if the endpoint we want is / graphql and if the authenticated user is what we want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = strapi =&amp;gt; {
  return {
    initialize() {
      strapi.app.use(async (ctx, next) =&amp;gt; {
        const handleErrors = (ctx, err = undefined, type) =&amp;gt; {
          if (ctx.request.graphql === null) {
            return (ctx.request.graphql = strapi.errors[type](err));
          }

          return ctx[type](err);
        };

        // check if it's a graphql request
        if (ctx.request.url === '/graphql' &amp;amp;&amp;amp; ctx.request.method === 'POST') {
          if (ctx.request &amp;amp;&amp;amp; ctx.request.header &amp;amp;&amp;amp; ctx.request.header.authorization) {
            try {
              // get token data
              const { id } = await strapi.plugins[
                'users-permissions'
              ].services.jwt.getToken(ctx);

              if (id === undefined) {
                throw new Error('Invalid token: Token did not contain required fields');
              }

              // check if the id match to the user you want
              if (id !== 'my-user-id') {
                return handleErrors(ctx, 'You are not authorized to access to the GraphQL API', 'unauthorized');
              }
            } catch (err) {
              return handleErrors(ctx, err, 'unauthorized');
            }
          } else {
            // if no authenticated, return an error
            return handleErrors(ctx, 'You need to be authenticated to request GraphQL API', 'unauthorized');
          }
        }

        await next();
      });


    }
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be authenticated you need to send a JWT in the header. See &lt;a href="https://strapi.io/documentation/v3.x/plugins/users-permissions.html#token-usage" rel="noopener noreferrer"&gt;here&lt;/a&gt; in Strapi's authentication documentation how to do it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Next.js:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validating fields:&lt;/strong&gt; The validation of form fields is not only used to guide your users, but also to guarantee the integrity of the information transmitted from the client to the server. This prevents a series of malicious codes from being entered into our Services. The user can still try to manipulate the data by editing the HTML in DevTools, but that is another problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CRSF:&lt;/strong&gt; Passing the parameter Content-Type: application / JSON, in our requests, forces our application not to use simple requests, and protects against attacks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;XSS:&lt;/strong&gt; &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html" rel="noopener noreferrer"&gt;This guide&lt;/a&gt; is very useful and shows some rules that it is good to follow when developing our front-end application so as not to have a headache afterward on security and XSS issues. &lt;a href="https://github.com/jagaapple/next-secure-headers" rel="noopener noreferrer"&gt;This Next.js plugin&lt;/a&gt; also helps to implement XSS Protection, helping the browser to sanitize vulnerable areas of your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Headers &amp;amp; ClickJacking:&lt;/strong&gt; Using X-Frame-Options: DENY or SAMEORIGIN, you prevent third parties from being able to run your Next.js application within a frame.&lt;br&gt;
The &lt;a href="https://github.com/jagaapple/next-secure-headers" rel="noopener noreferrer"&gt;next-secure-headers plugin&lt;/a&gt; helps you with that. In addition to implementing FrameGuard, it also implements XSS Protection, &lt;a href="https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy" rel="noopener noreferrer"&gt;contentSecurityPolicy&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Content-Type-Options" rel="noopener noreferrer"&gt;nosniff&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Download-Options" rel="noopener noreferrer"&gt;noopen&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/docs/Web/HTTP/Headers/Strict-Transport-Security" rel="noopener noreferrer"&gt;forceHTTPSRedirect&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/docs/Web/HTTP/Headers/Referrer-Policy" rel="noopener noreferrer"&gt;referrerPolicy&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/docs/Web/HTTP/Headers/Expect-CT" rel="noopener noreferrer"&gt;expectCT&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;JWT &amp;amp; Rolling Tokens:&lt;/strong&gt; You can implement JWT, for the authentication of your App to guarantee the integrity of your API and access to it, &lt;a href="https://medium.com/@xfor/apollo-next-js-refresh-token-authentication-flow-15e5f45df5a3" rel="noopener noreferrer"&gt;this is a good tutorial&lt;/a&gt; that teaches this&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;More:&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://next-auth.js.org/" rel="noopener noreferrer"&gt;NextAuth.js:&lt;/a&gt;&lt;/strong&gt; A plugin to help you with security in the authentication of your Next.js app&lt;/p&gt;

&lt;h2&gt;
  
  
  SSL:
&lt;/h2&gt;

&lt;p&gt;One step before we publish our site for production is to set our domain and server to the HTTPS protocol. HTTPS protects our requests from being targeted by Man In the Middle attacks and is also &lt;a href="https://www.agenciamestre.com/seo/https-e-resultados-no-google/" rel="noopener noreferrer"&gt;crucial for SEO&lt;/a&gt; as it impacts Google's ranking.&lt;/p&gt;

&lt;p&gt;Some ways to get free SSL certificates for your website are to use the service of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://letsencrypt.org/" rel="noopener noreferrer"&gt;Lets Encrypt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sslforfree.com/" rel="noopener noreferrer"&gt;SSL For Free&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/certificate-manager/" rel="noopener noreferrer"&gt;AWS Certificate Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zerossl.com/" rel="noopener noreferrer"&gt;ZeroSSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cloudflare.com/pt-br/ssl/" rel="noopener noreferrer"&gt;CloudFlare SSL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  APIS Caching:
&lt;/h2&gt;

&lt;p&gt;Although it is not only a concern with security but also with performance, APIS caching can be recommended so that your site can work even in offline environments, but when it comes to dynamic data, it ends up being not recommended, only for data that is not. constantly change. This is a topic that requires an article just for him, but if you feel interested in knowing more about it I recommend reading the following articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web.dev/cache-api-quick-guide/" rel="noopener noreferrer"&gt;Web.dev: Cache API: Quick Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/pt_br/apigateway/latest/developerguide/api-gateway-caching.html" rel="noopener noreferrer"&gt;Amazon API Gateway: API Caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.cloudflare.com/hc/en-us/articles/200504045-Using-Cloudflare-with-your-API" rel="noopener noreferrer"&gt;Using Cloudflare with your API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://graphql.org/learn/caching/" rel="noopener noreferrer"&gt;GraphQL Caching&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Strapi's Safety Roadmap:
&lt;/h2&gt;

&lt;p&gt;The Strapi team is planning some features that can help in future releases on security issues:&lt;/p&gt;

&lt;p&gt;This is the &lt;a href="https://portal.productboard.com/strapi/1-public-roadmap/tabs/2-under-consideration" rel="noopener noreferrer"&gt;Product Board link&lt;/a&gt;. In it, we see that the Strapi team plans features such as 2FA (Two-factor authentication), Rolling Token (JWT), SSO (Google, Twitter, Facebook, GitHub), among others that are already being tested: as Permissions and Rules per user and Permissions at field levels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking tools:
&lt;/h2&gt;

&lt;p&gt;There are some sites and tools on the web that test how secure our application is. Below are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://sentry.io/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt;:&lt;/strong&gt; Sentry is a tool for monitoring web apps errors. It supports several technologies and platforms. It can be easily integrated with &lt;a href="https://github.com/BrunoScheufler/graphql-middleware-sentry" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt;, &lt;a href="https://strapi.io/documentation/3.0.0-beta.x/guides/error-catching.html" rel="noopener noreferrer"&gt;Strapi&lt;/a&gt; or &lt;a href="https://leerob.io/blog/configuring-sentry-for-nextjs-apps" rel="noopener noreferrer"&gt;Next.js.&lt;/a&gt; It has a free version for developers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sqreen:&lt;/strong&gt; Sqreen is a webapps security monitoring platform. It can bring real-time data from potential exploits, protect you from attacks and malicious activities.&lt;br&gt;
Strapi supports Sqreen.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;First: &lt;a href="https://my.sqreen.com/signup?&amp;amp;referrer=aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8=" rel="noopener noreferrer"&gt;create a Sqreen trial account&lt;/a&gt;&lt;br&gt;
Second: set up your organization on the Sqreen dashboard&lt;br&gt;
Third: &lt;a href="https://strapi.io/documentation/3.0.0-beta.x/guides/secure-your-app.html" rel="noopener noreferrer"&gt;set up Sqreen on Strapi&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In Next.js you can also use Sqreen, but the configuration is a little more complicated&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;First&lt;a href="https://my.sqreen.com/signup?&amp;amp;referrer=aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8=" rel="noopener noreferrer"&gt;: create a Sqreen trial account&lt;/a&gt;&lt;br&gt;
 Second: set up your organization on the Sqreen dashboard&lt;br&gt;
 The third :&lt;a href="https://nextjs.org/docs/advanced-features/custom-server" rel="noopener noreferrer"&gt;configure Next.js to use a Custom-Server&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.sqreen.com/nodejs" rel="noopener noreferrer"&gt;Configure Sqreen for Node.js&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://lgtm.com/" rel="noopener noreferrer"&gt;LGTM&lt;/a&gt;:&lt;/strong&gt; LGTM is an open-source tool used by major players in the market, such as Google, Microsoft, Nasa, and Dell, which checks for vulnerabilities in your code through a repository on Github or BitBucket.&lt;br&gt;
It has an automatic code review tool and is very powerful, it has alerts to warn you about problems in the code and also comparisons and history.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://sonarcloud.io/" rel="noopener noreferrer"&gt;SonarCloud&lt;/a&gt;:&lt;/strong&gt; SonarQube is a very powerful tool that not only checks for bugs and vulnerabilities in your code but also some parameters like Code maintainability, Test Coverage, Codesmells, Code duplication, it analyzes your code and can stop a P / R or M / R on Github, GitLab, Azure DevOps or BitBucket if it does not reach the expected code quality. SonarCloud also has a plugin for IDES that checks in real-time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://observatory.mozilla.org/" rel="noopener noreferrer"&gt;Mozilla Observatory:&lt;/a&gt;&lt;/strong&gt; Mozilla tool that will help bring Insights about the security of your website.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://ssltools.digicert.com/checker/views/checkInstallation.jsp" rel="noopener noreferrer"&gt;DigiCert SSL Tools:&lt;/a&gt;&lt;/strong&gt; It will check your SSL certificate data, show possible vulnerabilities, the Certificate Chain and the Server Configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.ssllabs.com/ssltest" rel="noopener noreferrer"&gt;Qualys SSL Labs:&lt;/a&gt;&lt;/strong&gt; Tool a little more complete than that of DigiCert.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://pentest-tools.com/website-vulnerability-scanning/website-scanner" rel="noopener noreferrer"&gt;Pen-test Tool: Website Vulnerability:&lt;/a&gt;&lt;/strong&gt; Website that has SQL Injection checking, XSS, Inclusion of files, Execution of remote commands, however, it is paid.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;a href="https://sitecheck.sucuri.net/" rel="noopener noreferrer"&gt;Sucuri SiteChecker:&lt;/a&gt;&lt;/strong&gt; Sucuri is well known in the world of web security. Detects if your site is blacklisted on Google, if it has unsafe links, among other security parameters&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well guys, thanks if you got here and had patience, the intention was to have given you a general idea of how to mitigate and solve various security and vulnerability problems in web applications with Next.js and Strapi, before we started using Stack, being that the concepts mentioned here can be used and verified in any web application not only with Node.js and JavaScript / TypeScript but with other languages and that use Rest APIs or GraphQL Apis. This is a very extensive subject that could yield several articles, but I tried to summarize in this one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://snyk.io/vuln/npm:strapi" rel="noopener noreferrer"&gt;Strapi Vulnerabilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vulmon.com/searchpage.php?q=next.js&amp;amp;sortby=byrelevance&amp;amp;remote=on&amp;amp;local=on&amp;amp;physical=on&amp;amp;nanalyzed=on" rel="noopener noreferrer"&gt;Vulnerabilities in Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html" rel="noopener noreferrer"&gt;Cross Site Scripting Prevention Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.imperva.com/learn/application-security/clickjacking/" rel="noopener noreferrer"&gt;Clickjacking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apollographql.com/blog/securing-your-graphql-api-from-malicious-queries-16130a324a6b" rel="noopener noreferrer"&gt;Securing your GraphQL API from Malicious Queries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.petecorey.com/blog/2017/06/12/graphql-nosql-injection-through-json-types/" rel="noopener noreferrer"&gt;GraphQL NoSQL Injection through JSON Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/GraphQL%20Injection" rel="noopener noreferrer"&gt;GraphQL Injection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>frontend</category>
      <category>strapi</category>
      <category>security</category>
    </item>
    <item>
      <title>Why use Next.js + Strapi?</title>
      <dc:creator>Ruben Marcus</dc:creator>
      <pubDate>Fri, 07 May 2021 02:59:14 +0000</pubDate>
      <link>https://dev.to/rubenmarcus/why-use-next-js-strapi-16b1</link>
      <guid>https://dev.to/rubenmarcus/why-use-next-js-strapi-16b1</guid>
      <description>&lt;p&gt;At this article I will show you the advantages of doing a website with Strapi in the backend and Next.js in the frontend&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;at the time I wrote this article back in 2020, Directus was using an old Zend Framework in PHP that made a very interesting project full of features buggy,and not so easy to deploy and mantain as Strapi&lt;/p&gt;

&lt;p&gt;But as &lt;a href="https://dev.to/designmatty"&gt;Matt Williams&lt;/a&gt; stated in the comments the Directus team made an incredible effort rewriting their entire CMS in Node.js and soon in Laravel 8 too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  First of all… What is Headless CMS?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcmwucc3i3zgy5l9mcpu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcmwucc3i3zgy5l9mcpu.jpg" alt="Headless x Traditional CMS" width="700" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In short, it is a content management system like WordPress, Drupal or Contentful in which content management is separate from the presentation layer (Front-end).&lt;/p&gt;

&lt;p&gt;The main advantage of this approach is that it is tech independent, which means that the website (can be made in SPA frameworks or as you wish), native apps or can be created using the tools or tech you want.&lt;/p&gt;

&lt;p&gt;The main disadvantage is that you need to manage two or more web applications instead of one. (Which can be a disadvantage, depending on the formation of your team.)&lt;/p&gt;

&lt;p&gt;There are CMS that come as Headless standard (API-based), and some that are GIT-based, and generate static websites.&lt;/p&gt;

&lt;p&gt;And others that are also based on API but that do not come in this architecture by default and it is necessary to use plugins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The advantage of being Headless and API-based by default is that:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you have a source of information and can make many applications for different devices from it.&lt;/li&gt;
&lt;li&gt;The fact that it is a core functionality of the CMS, indicates that the chance of support and updates to the Headless API are greater, whereas if it is a plugin the chance of not being supported may be more likely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to know more about Headless CMS,than  take a look here: &lt;a href="https:%20/headlesscms.org" rel="noopener noreferrer"&gt;https: /headlesscms.org/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Strapi?
&lt;/h2&gt;

&lt;p&gt;Strapi is an Open Source CMS, made in Node.js and MongoDb, it also supports MYSQL, MariaDB, SQLite and PostgreSQL.&lt;/p&gt;

&lt;p&gt;Comes with easy deployment to AWS, Digital Ocean , Heroku and many other cloud services.&lt;/p&gt;

&lt;p&gt;It has rich documentation and several tutorials on how to use the CMS.&lt;/p&gt;

&lt;p&gt;It is possible to install &lt;a href="https://strapi.io/documentation/3.0.0-beta.x/installation/cli" rel="noopener noreferrer"&gt;locally via CLI&lt;/a&gt; or using &lt;a href="https://github.com/strapi/strapi-docker" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;, or using online services such as &lt;a href="https://strapi.io/documentation/3.0.0-beta.x/installation/platformsh" rel="noopener noreferrer"&gt;Platform.sh&lt;/a&gt; or &lt;a href="https://strapi.io/documentation/3.0.0-beta.x/installation/digitalocean-one-click" rel="noopener noreferrer"&gt;Digital Ocean&lt;/a&gt;, or wherever you want.&lt;/p&gt;

&lt;p&gt;It is possible to do unit tests with Jest, or other test frameworks, since Strapi has a configurable webpack.&lt;/p&gt;

&lt;p&gt;Strapi, also has webhooks to trigger actions for other applications.&lt;/p&gt;

&lt;p&gt;Strapi's architecture is very simple and well-founded, it explains how to write plugins, how to model the Strapi API, how to manage the content to be exported.&lt;/p&gt;

&lt;p&gt;Strapi's learning curve might be between low and medium, it depends on the developer's knowledge with Node.js and the concept of CMS Headless, if the developer has any doubts he can take a look at the existing examples, tutorials or documentation.&lt;/p&gt;

&lt;p&gt;It is possible to restrict JWT apis calls to Strapi user groups.&lt;/p&gt;

&lt;p&gt;Internationalization is only possible with a workaround, creating fields suffixed by languages&lt;/p&gt;

&lt;p&gt;The main competitor of Strapi in the Node.js world is Ghost, and OpenSource is Directus (made in PHP), also WordPress with its Rest Api that since version 4.7 is part of the WordPress Core and no longer made by plugin.&lt;/p&gt;

&lt;p&gt;Of these 4 Open Source options, I consider Strapi the better, because you understand how simple it is to manage and extend it.&lt;/p&gt;

&lt;p&gt;WordPress in addition to security issues, has a different base concept than Strapi. You can achieve the same goal as Strapi, but by making more settings and using various plugins.&lt;/p&gt;

&lt;p&gt;Ghost presents a somewhat similar scenario, but often to do the same thing you do on Strapi you will need more work for the same thing. &lt;/p&gt;

&lt;p&gt;Ghost is very good on the security side, but on the content side, Strapi is simpler and more complete.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://directus.io/" rel="noopener noreferrer"&gt;Directus&lt;/a&gt; is one of the CMS that presents, a proposal very similar to Strapi, but its stack is made in PHP, and has bug reports critical by users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Next.js?
&lt;/h2&gt;

&lt;p&gt;With the rise of SPAS frameworks, going from Angular.js, React, Angular 2+ and Vue,a major faced problem from apps rendered on the client,face it is the issue of SEO.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frameworks like Next.js come to solve this problem.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Rendering the application via SSR (Server Side Rendering) or SSG (Static Site Generation),than the search engine can read the content of your page, and render it for show in its results.&lt;/p&gt;

&lt;p&gt;But the benefits go beyond that. Next.js increases the loading performance of your application. &lt;/p&gt;

&lt;p&gt;In a basic test on Google LightHouse (we will address this soon), an application with create-react-app x a Next.js SSR application, had a first meaningful paint with 87% less time than a React CSR application (Client-side Rendering), this is due to Next.js already render part of your application on the Server, bringing the content on the screen before loading everything on the client.&lt;/p&gt;

&lt;p&gt;It has a folder and links scheme that also allows the lazy-loading of modules, as well as automatic code-splitting.&lt;/p&gt;

&lt;p&gt;You can choose which pages you will render on the server and which you will render statically, making it a Hybrid app.&lt;/p&gt;

&lt;p&gt;Next.js supports AMP (Acellerated Mobile Pages): Where it wont render anything from Node.js and React, and only pages in AMP format.&lt;/p&gt;

&lt;p&gt;Next.js also supports the entire range of CSS universe, from preprocessors such as SASS, LESS and Stylus, as well as CSS Modules, Styled Components, CSS-in-JS, TailWind CSS, Bootstrap etc.&lt;/p&gt;

&lt;p&gt;Next.js has a very strong focus on performance, and has tools for you to measure that. (This will be the subject of a separate article).&lt;/p&gt;

&lt;p&gt;We are able to use Next.js also with TypeScript, assuring how we handle our application data using interfaces and types.&lt;/p&gt;

&lt;p&gt;Inside Next.js you can also do DynamicImports, using the ES2020 syntax, and generating components dynamically.&lt;/p&gt;

&lt;p&gt;These are some benefits of Next.js, in addition to solving and helping us with the SEO problems of the SPA frameworks, it gives us the entire React ecosystem, to be able to work, in addition to helping us, with a lean structure and a very rich documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;some companies using Next.js&lt;/strong&gt;: GoDaddy,Netflix,Marvel,Invision App, Tencent, Tiktok, Uber, Trip.com, HostGator, Auth0, Binance, Staples, TicketMaster, Playstation, IGN, AT&amp;amp;T, Hulu, Twitch, Nike, Lego, Material UI, Expo, Ferrari, Avocode, Styled Components, Volvo, The Economist,Workable, Vodafone, Coinmarketcap, Monday, Elastic, History Channel , A&amp;amp;E Tv, Lifetime, Hackernoon, Spotify, Pier, DAZN, Apify,CloudBees, Deno,Crazygames.com&lt;/p&gt;

&lt;h2&gt;
  
  
  Next.js x Nuxt x Angular Universal x other React SSR Frameworks:
&lt;/h2&gt;

&lt;p&gt;There are other frameworks, which compete directly with Next.js &lt;/p&gt;

&lt;p&gt;The idea is not to make a comparison between them. But basically each one follows a tool, be it Nuxt.js with Vue, or Angular with Angular Universal.&lt;/p&gt;

&lt;p&gt;The idea is not to make a comparison here, because that would be a theme for an entire article, just to give an idea that there are other options on the market.&lt;/p&gt;

&lt;p&gt;Within the React ecosystem there are other ways to achieve the same goal, either with &lt;a href="https://github.com/jaredpalmer/after.js" rel="noopener noreferrer"&gt;After.js&lt;/a&gt;, &lt;a href="https://github.com/jaredpalmer/razzle" rel="noopener noreferrer"&gt;Razzle&lt;/a&gt; or &lt;a href="https://github.com/alexnm/react-ssr" rel="noopener noreferrer"&gt;React-SSR&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting witn Next.js + Strapi: Boilerplates
&lt;/h2&gt;

&lt;p&gt;Boilerplates are ready to use codes that allow us to start an application without having to configure it from scratch.&lt;/p&gt;

&lt;p&gt;They are very useful to go out coding our application without wasting time with installations and configurations.&lt;/p&gt;

&lt;p&gt;Below I will mention some that I think are good to start in the Next.js and Strapi universe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/strapi/strapi-starter-react-blog" rel="noopener noreferrer"&gt;Strapi Next.js Blog Boilerplate&lt;/a&gt; (made by the Strapi team)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/vercel/next.js/tree/canary/examples/cms-strapi" rel="noopener noreferrer"&gt;Next.js Strapi Example&lt;/a&gt; (made by the Next.js team)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://strapi.io/documentation/" rel="noopener noreferrer"&gt;Strapi Documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://nextjs.org/docs" rel="noopener noreferrer"&gt;Next.js documentation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/strapi/10-reasons-why-you-should-use-a-headless-cms-cea598880dc7" rel="noopener noreferrer"&gt;10 Reasons you should use a Headless CMS&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>strapi</category>
      <category>headless</category>
    </item>
  </channel>
</rss>
