Using GitSearch
How to find developers on GitHub, what this tool can and cannot see, and how to get more out of a search that has hit a wall.
1. What this tool does, and what it cannot do
GitSearch searches the public profiles of people who have a GitHub account. You type what you are looking for — a language, a city, a word from someone's bio — and it finds developers whose public profile matches, then keeps a copy so the same search is instant next time.
Four limits are worth knowing before you start.
GitHub returns at most 1,000 results for any one search
This is GitHub's rule, not ours, and there is no way around it directly. A search for Python developers in Germany might genuinely match forty thousand people; you will be able to page through one thousand of them. Section 8 explains how to slice a broad search into several narrower ones that between them reach the rest.
Only public information
Everything here is what each person chose to publish on their own profile. Nothing is inferred, scraped from web pages, bought from a third party, or combined with data from anywhere else. If a profile's location is blank, we do not know where they are.
Most people have not published an email address
An email only appears if the person deliberately put one on their GitHub profile. Expect the majority of results to have none. There is a second, narrower way to find one — see section 6 — but it does not work for everyone either, and it comes with conditions.
The data is a snapshot, not a live view
Results are stored so that repeating a search costs nothing. Every result row and profile page tells you how old its data is, and anything past the cache lifetime is marked stale. You can refresh any profile from its own page.
2. Loose search: just type what you mean
The default search box takes plain words in any order. Type python belgrade serbia and it works out that Python is a programming language, that Belgrade and Serbia are places, and searches for people matching any of them.
Things that work:
- Any order.
berlin reactandreact berlinare the same search. - Local spellings.
beograd,srbija,deutschland,münchen,warszawaall resolve to the names GitHub indexes. We recognise 533 places and 815 programming languages, including the short forms people actually type —js,golang,nyc,blr. - Quoted phrases.
"machine learning" zurichkeeps the phrase together instead of searching for two separate words. - Exclusions. Put a minus in front of anything you want left out:
python berlin -recruiter. - Filler is ignored.
react developer berlindrops “developer”, because it appears on almost every profile and would not narrow anything.
Why one search runs several queries
GitHub's search is stricter than it looks. language:Python only matches people whose public repositories are in Python — not someone who writes Python at work and has none online. location:Belgrade only matches people whose location field says exactly that — not someone who wrote “Beograd”.
So instead of one query, we run up to four readings of what you typed — from the most precise to the widest — and combine the results. That is why a loose search finds people a single query would miss.
The How we searched panel above your results shows every query that was sent, in GitHub's own syntax, with a sentence explaining what each one was looking for. Nothing is hidden. If you disagree with an interpretation, click any query to open it in strict mode and edit it yourself.
When a word means two things
go is a programming language and an ordinary word. split is a Croatian city and a verb. Rather than guess, we search both readings and say so in the panel:
go was read as the Go language and as the word “go” — both were searched.
Local only
Tick Local only next to the search box to search just the profiles already stored, without contacting GitHub. It is instant, it uses none of the daily GitHub allowance, and it is the right choice when you are refining a search you have already run.
3. Strict search: one box per filter
The Strict tab gives you a form with a field for each thing GitHub can filter on. It builds the query as you type and shows it to you before you run it, so there are no surprises.
| Field | Finds | Example |
|---|---|---|
| Login | One exact GitHub username. | octocat |
| Full name | The display name as a whole. Better than Name contains when you know the whole name. | Mona Lisa |
| Name contains | Part of someone's display name. | mona |
| The part of an address before the @. GitHub cannot search the domain, so searching for a company by its mail domain does not work. | mona | |
| Locations | The person's location field. Several places means any of them. | Belgrade, Serbia |
| Languages | The languages in their public repositories. Several means any of them. | Python, Go |
| Public repositories | How many public repositories they have. | >10 · 10..50 · <5 |
| Followers | How many people follow them. | >100 · 50..500 |
| Account created | When they joined GitHub. Useful for slicing a search that hit the 1,000 cap. | >2020-01-01 · 2015-01-01..2020-12-31 |
| Keywords | Free text, searched across login, name, email and bio — and nothing else. It does not search repository contents. | kubernetes |
| Exclude | Terms to leave out. | recruiter, student |
| Sponsorable | Only people who can be sponsored through GitHub. | — |
| Sort | Best match, followers, repositories or join date. | — |
Ranges
Anywhere a number or date is asked for you can give a range: >100, >=100, <5, 10..50, 10..*, *..50. We also accept 10-50 and 10 to 50 and convert them for you.
Writing the query yourself
Tick Write the query myself to type GitHub search syntax directly. Anything GitHub's user search accepts works here, and type:user is added if you leave it out so that organisations do not appear.
4. The rules, and the four that catch people out
GitHub's search syntax has some sharp edges. The strict form enforces all of these before it will run, so you get a sentence rather than a rejection, but they are worth understanding.
1. Repeating a filter means “or”. Different filters mean “and”.
location:Berlin location:Munich finds people in either city. location:Berlin language:Go finds people in Berlin who also write Go. This is the only way to express “or”, and it costs nothing against the operator limit below.
2. There are no parentheses
You cannot write (location:Berlin OR location:Munich) AND language:Go. GitHub rejects it. Repeat the qualifier instead, as above.
3. At most five explicit AND / OR / NOT
Written-out operators are limited to five per query. Since repeating a qualifier is a free “or” and a leading minus is a free “not”, you will rarely need any.
4. 256 characters, total
A longer query is rejected outright. The strict form shows a character counter; loose search shortens its own queries if they would overrun and tells you it did.
And one that is not a rule
Keywords search only the login, name, email and bio. They do not search repository names, repository descriptions, README files or code. Searching for kubernetes finds people who wrote the word in their bio, not people who have worked on it.
5. Reading the results
Each row is one person. The bar above them tells you:
- How many. “1–20 of 1,000” means you can reach a thousand. If the true total is higher you will see a note saying so.
- Where it came from. local cache means the answer came from profiles already stored and GitHub was not contacted at all. GitHub means this page was fetched live.
- How old. “oldest record 12 days old” is the age of the least fresh profile on the page. A person's location or job may have changed since.
On each row:
- The name opens their GitHub profile in a new tab. The @login opens our stored copy, with their repositories and language breakdown.
- available for hire means they ticked that box on GitHub themselves. It is a strong signal and worth filtering on.
- matched 3 readings means several of the queries we ran found this person — usually a sign of a good match.
- stale means the stored data is older than the cache lifetime. Open the profile and press Refresh for current data.
- Emails carry a badge saying where they came from: profile for an address the person published, and commit for one found in commit metadata. The difference matters — see the next section.
Browse local
The Browse local tab filters everything already stored, without ever contacting GitHub. Filter by location, language, company, follower range, whether they have an email, and how fresh the record is. It is the fastest way to work through profiles you have already collected, and it uses none of the daily allowance.
6. Emails, and the second way to find one
Most GitHub users do not publish an email address. When one is present on the profile it appears with a profile badge and you can use it.
When there is none, the email slot offers Fetch from repos. Git records an author address inside every commit, and GitHub publishes that for public repositories. Pressing the button asks GitHub for up to thirty recent commits it has already attributed to that person, across a handful of their repositories, and looks for an address.
What it will and will not return:
- Addresses GitHub generates to protect people (
@users.noreply.github.com) are discarded. - Bot and automation addresses, and role addresses like
admin@, are discarded. - An address we cannot confidently attribute to that person is discarded, so a colleague's address in their repository is not recorded against their name.
- If nothing is found, the button becomes “checked on <date>, retry” so nobody spends the allowance twice on the same silence.
Use these addresses thoughtfully. An address in commit metadata was published to attribute code, not to be contacted. That is why it is labelled differently, why the lookup never happens automatically, and why your administrator can switch the feature off for your whole account. Whether it is appropriate to contact someone on it is a judgement your organisation has to make — see our privacy policy.
Looking several up at once
Select some rows and press Fetch missing emails. It works through them one at a time and shows progress. It only touches profiles that have no address yet.
7. Exports
Tick the rows you want, or leave nothing ticked to export everything the search matched, then choose a format.
- CSV — every column, opens in Excel or Google Sheets. Accented names come through correctly.
- XLSX — the same columns as a real spreadsheet, with a frozen bold header row, sensible column widths and filters switched on.
- LinkedIn — an import file for LinkedIn Recruiter. Exactly three columns (
username,name,email), one row per address, and only people who have an email. Anyone without one is left out, because the file would be useless with a blank there. GitSearch offers to look for missing addresses first.
Exporting everything
Choosing “All results” does more work than exporting a page: it walks the whole result set, loads full details for anyone not already stored, and only then builds the file. For a thousand people that takes a few minutes, and you will see it counting up. Do not close the tab.
An export can never contain more than a thousand people, for the reason in section 1.
8. Getting past 1,000 results
GitHub caps every search at a thousand results. The way around it is to turn one broad search into several narrower ones that do not overlap, and run them in turn.
The two best fields to slice on are join date and follower count, because every person has exactly one value for each, so the slices cannot double-count.
Slicing by join date
Suppose location:Germany language:Python reports far more than a thousand. Run it several times in strict mode with an Account created range:
*..2013-12-312014-01-01..2017-12-312018-01-01..2020-12-312021-01-01..2023-12-312024-01-01..*
Each returns up to a thousand, and together they cover everyone. If a slice still reports a thousand, split that one further.
Slicing by followers
The same idea with Followers: 0..4, 5..19, 20..99, 100..499, >=500. This one has a useful side effect — the high-follower slices are small and tend to contain the most visible people, so start there if you want the best candidates first rather than all of them.
Slicing by place
Instead of one country, run each of its cities. Less exact, because some people write only the country and some only the city, so slices overlap and a few people appear twice — but it is often the most natural way to divide a search up.
Everything you collect goes into the same shared store, so after running several slices you can use Browse local to work through the combined set as one list, and export it in one file.