Count lines of code by type
See how much of a file is real code: the sample function gives 6 lines, of which 4 are code, 1 is a comment and 1 is blank, judged by the comment rules of the language you pick. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Language
- Javascript
- Total lines
- 6
- Blank lines
- 1
- Comment lines
- 1
- Code lines
- 4
Measure a source snippet or complete file with comment rules that match its programming language. The counter separates every physical line into exactly one category: blank, comment, or code, while also returning the total. It recognizes common line and block comment forms, ignores comment-like markers inside quoted strings, and treats mixed code-and-comment lines as code. This makes the result useful for quick repository reports, review preparation, migration estimates, and repeatable automation without uploading a project or installing a language-specific tool.
Choose the language and preserve the source text
Submit the source exactly as it appears and select its language from the supported list. The language matters because the same characters have different meanings across ecosystems: a hash starts a comment in Python and shell scripts, two slashes start one in JavaScript and Java, two hyphens introduce a SQL comment, and HTML uses a paired marker. The counter uses the selected syntax table rather than guessing from a filename or from the contents.
That explicit choice makes automated results reproducible and prevents an ambiguous snippet from being silently classified under the wrong rules. Physical lines are separated using LF, CRLF, or bare carriage-return boundaries, so source copied from common operating systems is handled consistently. A final newline creates an empty physical line after the last separator and is therefore included as a blank line.
An empty string similarly represents one empty physical line. Do not pre-remove comments, trim the entire input, or normalize away trailing newlines if those details should appear in the measurement.
Understand how each line is classified
Every physical line contributes once to one mutually exclusive category. A line containing only spaces or tabs is blank unless it occurs inside an open block comment. A line containing comment text but no executable token is a comment line.
A line with any code token is a code line, even when a trailing or embedded comment also appears on that line. This convention avoids double counting and guarantees that blank lines, comment lines, and code lines add up to the reported total. Block comments remain active across newline boundaries until their closing marker is found, so interior lines are counted as comments.
If code appears before a block comment begins or after it closes, the line is code. The scanner also tracks single quotes, double quotes, backticks, and backslash escapes while examining a line. Consequently, a URL containing two slashes or a string such as “# not a comment” remains code rather than starting a comment.
The result is a practical source-line count, not a parser-derived statement count: multiple statements on one physical line still contribute one code line, and a statement spread across several lines can contribute several code lines.
Use the totals consistently in reports
Because the categories are exhaustive and non-overlapping, you can validate a result by adding the last three values and comparing the sum with the total. Use code lines as a rough measure of implementation volume, comment lines as documentation context, and blank lines as formatting context, but avoid treating any of these figures as a direct measure of productivity or quality. Generated files, vendored dependencies, tests, and compact coding styles can change line totals dramatically without reflecting equivalent engineering effort.
For repository reporting, decide which files belong in scope before calling the counter, process each file with its correct language, and aggregate fields only under a documented policy. Save the language and counting convention with historical measurements so later comparisons use the same basis. The implementation is deterministic and performs no network calls, file discovery, filename inference, clock access, or random sampling.
It examines only the supplied text.
What you can do with it
Prepare a repository inventory
Classify individual source files and aggregate consistent code, comment, and blank line totals for an internal report.
Estimate a migration scope
Compare the physical implementation volume of selected components before planning a language or framework migration.
Track generated source changes
Record deterministic line categories for generated artifacts and flag unexpected shifts in code or comment volume.
FAQ
What does one count cost?
The browser experience can run the same deterministic logic locally.
Does a line with code and a trailing comment count twice?
No. It counts once as a code line, keeping all output categories mutually exclusive.
Are comment markers inside strings treated as comments?
No. Markers inside recognized quoted strings are treated as source code rather than comment starts.
How are multiline block comments counted?
Comment-only lines from the opening marker through the closing marker count as comment lines; a line that also contains code counts as code.
Does it detect the programming language by itself?
No. You pick the language from the list and its comment rules are applied. It never guesses from a file name or from the contents, so the same text always gets the same count and an ambiguous snippet is not judged by the wrong rules.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/dev2/count-lines-of-code \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"function add(a, b) {\n // Return the sum\n return a + b;\n}\n","language":"javascript"}'const res = await fetch("https://api.kit.forhosting.com/dev2/count-lines-of-code", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "function add(a, b) {\n // Return the sum\n return a + b;\n}\n",
"language": "javascript"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/dev2/count-lines-of-code",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "function add(a, b) {\n // Return the sum\n return a + b;\n}\n",
"language": "javascript"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/dev2/count-lines-of-code", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"function add(a, b) {\\n // Return the sum\\n return a + b;\\n}\\n","language":"javascript"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"function add(a, b) {\n // Return the sum\n return a + b;\n}\n","language":"javascript"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/dev2/count-lines-of-code", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"text": "function add(a, b) {\n // Return the sum\n return a + b;\n}\n",
"language": "javascript"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "dev2.count_lines_of_code",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Choose the language and preserve the source text
If the requested language is not in the declared list, the call returns an invalid input error instead of applying a misleading generic rule.
Use the totals consistently in reports
The response returns the normalized language name together with total_lines, blank_lines, comment_lines, and code_lines. That narrow behavior is useful in CI jobs and editor integrations because identical inputs produce identical JSON, while project traversal and exclusion rules remain under the caller’s control.
Technical questions
What happens when the language is unknown?
The capability returns an invalid_input error with an unrecognized-language message instead of guessing comment rules.