AI tools

Free AI code reviewer

Paste your code. Get the bugs, security holes and edge cases a senior reviewer would flag, ranked by severity, each with a concrete fix.

How it works

  1. Paste a function, class or short file in any language, and add a line about what it should do and where it runs if you can.
  2. Pick a focus (full review, bugs, security, performance or readability) and click Review my code.
  3. Get a verdict and a ranked list of issues, each quoting the code, explaining what breaks and showing the fix. Apply the fixes and run your tests.

Examples

Sample results for the inputs shown, so you can see the format and quality before you try it.

Example 1: input

Code to review: def get_orders(db, customer_id, statuses=[]): statuses.append("open") q = f"SELECT * FROM orders WHERE customer_id = {customer_id} AND status IN ({','.join(repr(s) for s in statuses)})" rows = db.execute(q).fetchall() total = 0 for r in rows: total += r["amount"] return rows, total / len(rows)

Review focus: Full review

What the code should do: Returns a customer's orders and the average order amount. customer_id comes from the URL.

Example 1: output
Summary: Needs rework — customer_id goes straight from the URL into the SQL string, so this is an injection hole. Issues: 1. [High] q = f"SELECT * FROM orders WHERE customer_id = {customer_id} ..." Problem: customer_id comes from the URL and is pasted into the query. A value like 1 OR 1=1 returns every customer's orders. Fix: use placeholders and pass values separately: q = f"SELECT * FROM orders WHERE customer_id = ? AND status IN ({','.join('?' * len(s))})" rows = db.execute(q, [customer_id, *s]).fetchall() 2. [High] statuses=[] with statuses.append("open") Problem: the default list is created once and shared. Every call adds another "open", and a caller's own list is changed too. Fix: def get_orders(db, customer_id, statuses=None): s = list(statuses or []) + ["open"] 3. [High] total / len(rows) Problem: a customer with no orders raises ZeroDivisionError. Fix: average = total / len(rows) if rows else 0 4. [Medium] total += r["amount"] Problem: if amount is a float, sums of prices drift (0.1 + 0.2 != 0.3). Fix: store cents as integers or use Decimal. 5. [Low] SELECT * Problem: pulls every column, including ones added later. Fix: name the columns you use. Questions: Is db a sqlite3 connection? Placeholder syntax is ? for sqlite3 and %s for psycopg. What's good: Returning the rows and the average together saves the caller a second query.
Example 2: input

Code to review: async function sendReminders(users) { let sent = 0; users.forEach(async (u) => { if (u.email && !u.unsubscribed) { await mailer.send(u.email, template(u)); sent++; } }); console.log(`Sent ${sent} reminders`); return sent; }

Review focus: Bugs and edge cases

What the code should do: Nightly job, about 20,000 users.

Example 2: output
Summary: Ship after fixes — the function returns before any email is sent, so the count is always 0 and failures go unnoticed. Issues: 1. [High] users.forEach(async (u) => { ... }) Problem: forEach ignores the promises its callback returns. The function logs "Sent 0 reminders" and returns 0 while the sends are still running, and a failed send becomes an unhandled rejection. Fix: collect the promises and await them: const results = await Promise.allSettled(targets.map(u => mailer.send(u.email, template(u)))); const sent = results.filter(r => r.status === 'fulfilled').length; 2. [Medium] Starting all sends at once Problem: with 20,000 users, fixing issue 1 with a single Promise.all fires 20,000 requests together and will hit the mailer's rate limit. Fix: send in batches of 50 to 100, awaiting each batch, or use a small concurrency limiter such as p-limit. 3. [Medium] No record of who failed Problem: a rerun after a partial failure emails everyone again. Fix: log or store the ids of failed sends and mark successful ones as reminded. Questions: Does mailer.send retry on its own? If so, lower the batch size. What's good: Skipping unsubscribed users before sending, not after, is the right order.
Example 3: input

Code to review: app.get('/download', (req, res) => { const file = path.join(__dirname, 'uploads', req.query.name); res.sendFile(file); });

Review focus: Security

Example 3: output
Summary: Needs rework — anyone can read any file the server can read, including .env, by putting ../ in the name. Issues: 1. [High] path.join(__dirname, 'uploads', req.query.name) Problem: path traversal. name=../../.env resolves outside uploads, and path.join does not stop it. Fix: const base = path.resolve(__dirname, 'uploads'); const file = path.resolve(base, String(req.query.name || '')); if (!file.startsWith(base + path.sep)) return res.sendStatus(404); 2. [High] No access check Problem: nothing ties a file to the user asking for it, so one customer can download another's upload by guessing names. Fix: look the file up by an id the current user owns, and serve the stored path from your database instead of the query string. 3. [Low] Missing name Problem: /download with no name makes sendFile throw. Fix: return 400 when req.query.name is missing. Questions: Is there auth middleware in front of this route that I can't see? What's good: Nothing to add.

Tips for better results

  • Say where the input comes from. "customer_id comes from the URL" turns a style comment into a security finding.
  • Review one function or file at a time. Short pastes get specific findings; a whole repo pasted in gets general advice.
  • Include the load and runtime ("20,000 users a night, Node 20"). Performance and concurrency issues depend on it.
  • Treat the review as a second reader, not a test suite. Write a failing test for each High issue before you fix it.

FAQ

Is this AI code reviewer free?

Yes. Enter your email once to use it (you'll also get Something Big, our free weekly AI newsletter, and you can unsubscribe anytime). There's no account and no credit card.

Which languages does it review?

Any mainstream language: Python, JavaScript and TypeScript, Java, C#, Go, Ruby, PHP, SQL, Rust and more. It checks for the traps specific to each, such as mutable default arguments in Python or async callbacks inside forEach in JavaScript.

Can it replace a human code review?

No. It is good at the mechanical catches: injection, missing awaits, unhandled errors, edge cases. A teammate still needs to judge the design, the product logic and whether the change should exist at all.

Is it safe to paste company code?

Your code is sent to an AI model to write the review and is not published or saved to an account. Check your company's policy first, and never paste secrets, keys or customer data.

More free AI tools

Related prompts

Prefer to use ChatGPT or Claude directly? These free prompts do similar jobs.

Get the best free AI tools and prompts every week

Something Big is a free AI newsletter read by 50,000+ professionals. One email a week with the AI tools and prompts that actually work, plus what changed in AI and what to do about it.