Federal Recompete Finder - Instant Demo

Which 'expiring' federal contracts are real recompetes? Live from USAspending.gov: final end dates with option years, offers received last time, the incumbent's parent and scale against the SBA size limit - every row linked to its award record.

8 steps · shared by Klajdi · September 21, 2026
Make it your own →
No data is shared in this template. It contains only the recipe — column names and SQL logic. When you run it, your data is processed in your own browser and never leaves your machine.

What data it expects

GOVCON_ExpiringContracts.csv
award_id · VARCHARcurrent_end_date · DATEfinal_end_date · DATE<set-aside, offers, vehicle, incumbent, parent, incumbent awards per year, award_url> · VARCHAR
GOVCON_SizeStandards.csv
naics_code · VARCHARsize_limit_usd_millions · DOUBLEsize_limit_employees · BIGINT
QBO_ProfitAndLoss_Month.csv
section · VARCHARaccount · VARCHAR<one column per month, YYYY-MM> · DOUBLE

Connect QuickBooks Online or drop a CSV / Excel export with a similar layout — the AI adapts the workflow if your columns differ.

How it works — every step, readable

  1. 01Contracts with a period ending soon - VA, computer systems design (live, USAspending.gov)
    SELECT * FROM read_csv_auto('GOVCON_ExpiringContracts.csv', header=true, types={'award_id': 'VARCHAR', 'naics_code': 'VARCHAR', 'psc_code': 'VARCHAR', 'vehicle': 'VARCHAR'})
  2. 02SBA small-business size limits by industry (official table)
    SELECT * FROM read_csv_auto('GOVCON_SizeStandards.csv', header=true, types={'naics_code': 'VARCHAR'})
  3. 03Demo IT contractor - last 12 months of books (sample)
    SELECT section, account, CAST(COLUMNS(* EXCLUDE (section, account)) AS DOUBLE) FROM (VALUES
      ('Income', 'Federal contract revenue', 444600.0, 468879.84, 493608.96, 465454.08, 490464.0, 515923.2, 486645.12, 512385.12, 538574.4, 508173.12, 534643.2, 503287.2),
      ('Income', 'Commercial services revenue', 57950.0, 61114.68, 64337.92, 60668.16, 63928.0, 67246.4, 63430.24, 66785.24, 70198.8, 66236.24, 69686.4, 65599.4),
      ('Other Income', 'Interest income', 855.0, 901.69, 949.25, 895.1, 943.2, 992.16, 935.86, 985.36, 1035.72, 977.26, 1028.16, 967.86),
      ('Cost of Goods Sold', 'Direct labor', 248900.0, 262492.56, 276336.64, 260574.72, 274576.0, 288828.8, 272438.08, 286848.08, 301509.6, 284490.08, 299308.8, 281754.8),
      ('Cost of Goods Sold', 'Subcontractors', 83600.0, 88165.44, 92815.36, 87521.28, 92224.0, 97011.2, 91505.92, 96345.92, 101270.4, 95553.92, 100531.2, 94635.2),
      ('Cost of Goods Sold', 'Other direct costs', 19950.0, 21039.48, 22149.12, 20885.76, 22008.0, 23150.4, 21836.64, 22991.64, 24166.8, 22802.64, 23990.4, 22583.4),
      ('Expenses', 'Indirect salaries', 55100.0, 58109.04, 61173.76, 57684.48, 60784.0, 63939.2, 60310.72, 63500.72, 66746.4, 62978.72, 66259.2, 62373.2),
      ('Expenses', 'Fringe benefits', 38950.0, 41077.08, 43243.52, 40776.96, 42968.0, 45198.4, 42633.44, 44888.44, 47182.8, 44519.44, 46838.4, 44091.4),
      ('Expenses', 'Rent & facilities', 9310.0, 9818.42, 10336.26, 9746.69, 10270.4, 10803.52, 10190.43, 10729.43, 11277.84, 10641.23, 11195.52, 10538.92),
      ('Expenses', 'Software & IT', 7220.0, 7614.29, 8015.87, 7558.66, 7964.8, 8378.24, 7902.78, 8320.78, 8746.08, 8252.38, 8682.24, 8173.04),
      ('Expenses', 'Bids & proposals', 6555.0, 6912.97, 7277.57, 6862.46, 7231.2, 7606.56, 7174.9, 7554.4, 7940.52, 7492.3, 7882.56, 7420.26),
      ('Expenses', 'Professional fees', 4940.0, 5209.78, 5484.54, 5171.71, 5449.6, 5732.48, 5407.17, 5693.17, 5984.16, 5646.37, 5940.48, 5592.08),
      ('Expenses', 'Insurance', 3705.0, 3907.33, 4113.41, 3878.78, 4087.2, 4299.36, 4055.38, 4269.88, 4488.12, 4234.78, 4455.36, 4194.06),
      ('Other Expenses', 'Interest expense', 1330.0, 1402.63, 1476.61, 1392.38, 1467.2, 1543.36, 1455.78, 1532.78, 1611.12, 1520.18, 1599.36, 1505.56)
    ) AS t(section, account, "2025-09", "2025-10", "2025-11", "2025-12", "2026-01", "2026-02", "2026-03", "2026-04", "2026-05", "2026-06", "2026-07", "2026-08")
  4. 04Which ones really end? Final end date, options included
    WITH c AS (
      SELECT award_id, contract_type, COALESCE(CAST(vehicle AS VARCHAR), '') AS vehicle, description,
        awarding_agency, awarding_sub_agency, CAST(naics_code AS VARCHAR) AS naics_code, naics_description,
        TRY_CAST(start_date AS DATE) AS start_date, TRY_CAST(current_end_date AS DATE) AS current_end_date, TRY_CAST(final_end_date AS DATE) AS final_end_date,
        TRY_CAST(obligated_to_date AS DOUBLE) AS obligated_to_date, TRY_CAST(ceiling_value AS DOUBLE) AS ceiling_value,
        COALESCE(CAST(set_aside AS VARCHAR), '') AS set_aside, COALESCE(CAST(extent_competed AS VARCHAR), '') AS extent_competed,
        TRY_CAST(offers_received AS BIGINT) AS offers_received,
        incumbent, COALESCE(CAST(incumbent_parent AS VARCHAR), '') AS incumbent_parent, COALESCE(TRY_CAST(incumbent_flagged_small AS BOOLEAN), false) AS incumbent_flagged_small,
        TRY_CAST(incumbent_federal_contracts_avg_5y AS DOUBLE) AS incumbent_awards_per_year, TRY_CAST(incumbent_federal_contracts_latest_fy AS DOUBLE) AS incumbent_awards_latest_year,
        award_url, source
      FROM input_1
    )
    SELECT *,
      date_diff('month', current_end_date, final_end_date) AS option_months_remaining,
      date_diff('month', CURRENT_DATE, final_end_date) AS months_to_final_end,
      (final_end_date <= CURRENT_DATE + INTERVAL 18 MONTH) AS truly_ending,
      CASE WHEN final_end_date > CURRENT_DATE + INTERVAL 18 MONTH THEN 'Not a recompete yet - option years remain'
           WHEN date_diff('month', CURRENT_DATE, final_end_date) < 6 THEN 'Late - the solicitation is probably out'
           WHEN date_diff('month', CURRENT_DATE, final_end_date) < 12 THEN 'Now - 6 to 12 months out'
           ELSE 'Early - 12 to 18 months out, where challengers win' END AS capture_timing
    FROM c
    ORDER BY final_end_date
  5. 05Incumbent against the size limit, competition, who can bid
    WITH j AS (
      SELECT d.*, l.size_limit_usd_millions, l.size_limit_employees, l.limit_basis,
        ROUND(COALESCE(NULLIF(d.ceiling_value, 0), d.obligated_to_date) / GREATEST(date_diff('month', d.start_date, d.final_end_date) / 12.0, 1), 0) AS annual_value,
        (d.set_aside <> '') AS is_set_aside,
        regexp_replace(lower(d.incumbent), '[^a-z0-9]', '', 'g') <> regexp_replace(lower(d.incumbent_parent), '[^a-z0-9]', '', 'g') AND d.incumbent_parent <> '' AS has_bigger_parent
      FROM input_1 d
      LEFT JOIN input_2 l ON l.naics_code = d.naics_code
      WHERE d.truly_ending
    )
    SELECT *,
      CASE WHEN NOT is_set_aside THEN 'Not a set-aside'
           WHEN limit_basis <> 'annual receipts' OR size_limit_usd_millions IS NULL THEN 'Size limit is by headcount - cannot be tested from spending data'
           WHEN incumbent_awards_per_year IS NULL THEN 'No award history found'
           WHEN incumbent_awards_per_year > size_limit_usd_millions * 1e6 THEN 'Federal awards alone exceed the small-business limit'
           ELSE 'Within the small-business limit on federal awards' END AS incumbent_size_signal,
      (is_set_aside AND limit_basis = 'annual receipts' AND incumbent_awards_per_year > size_limit_usd_millions * 1e6) AS may_have_outgrown,
      (offers_received BETWEEN 1 AND 2) AS thin_competition,
      (vehicle <> '') AS vehicle_holders_only
    FROM j
  6. 06Your revenue from the books
    WITH long AS (
      UNPIVOT (SELECT * FROM input_1) ON COLUMNS(* EXCLUDE (section, account)) INTO NAME period VALUE amount
    ),
    recent AS (SELECT DISTINCT period FROM long WHERE regexp_matches(period, '^[0-9]{4}-[0-9]{2}$') ORDER BY period DESC LIMIT 12)
    SELECT ROUND(SUM(CASE WHEN section ILIKE '%income%' THEN amount ELSE 0 END), 0) AS your_revenue_12m,
           (SELECT COUNT(*) FROM recent) AS months_covered,
           'Revenue over the last 12 months of books - SBA judges size on a five-year average, so treat this as indicative' AS basis
    FROM long WHERE period IN (SELECT period FROM recent)
  7. 07Ranked target list - why each one, and whether you can carry it
    WITH s AS (SELECT * FROM input_1), you AS (SELECT * FROM input_2 LIMIT 1),
    scored AS (
      SELECT s.*, you.your_revenue_12m,
        (CASE WHEN may_have_outgrown THEN 3 ELSE 0 END) + (CASE WHEN thin_competition THEN 2 ELSE 0 END)
          + (CASE WHEN is_set_aside THEN 1 ELSE 0 END) + (CASE WHEN capture_timing LIKE 'Early%' OR capture_timing LIKE 'Now%' THEN 1 ELSE 0 END)
          + (CASE WHEN NOT vehicle_holders_only THEN 1 ELSE 0 END) AS score,
        CASE WHEN you.your_revenue_12m IS NULL OR you.your_revenue_12m <= 0 THEN 'Add your books to size this'
             WHEN annual_value <= 0.5 * you.your_revenue_12m THEN 'Prime-size - up to half your revenue a year'
             WHEN annual_value <= 2 * you.your_revenue_12m THEN 'Stretch - up to twice your revenue a year'
             ELSE 'Team - more than twice your revenue a year' END AS your_fit,
        CASE WHEN size_limit_usd_millions IS NULL THEN 'Size limit is by headcount'
             WHEN you.your_revenue_12m <= size_limit_usd_millions * 1e6 THEN 'You are under the $' || size_limit_usd_millions || 'M limit'
             ELSE 'You are OVER the $' || size_limit_usd_millions || 'M limit' END AS your_size_check
      FROM s, you
    )
    SELECT ROW_NUMBER() OVER (ORDER BY score DESC, annual_value DESC) AS rank,
      award_id, description AS what_it_is, awarding_sub_agency AS buyer, strftime(final_end_date, '%Y-%m-%d') AS final_end_date, months_to_final_end AS months_left, capture_timing,
      annual_value, set_aside, offers_received, vehicle, incumbent, incumbent_parent,
      ROUND(incumbent_awards_per_year, 0) AS incumbent_awards_per_year, size_limit_usd_millions, incumbent_size_signal,
      TRIM(BOTH ' ' FROM
        (CASE WHEN may_have_outgrown THEN 'Incumbent may be too big to rebid as small. ' ELSE '' END) ||
        (CASE WHEN has_bigger_parent THEN 'USAspending lists its parent as ' || incumbent_parent || '. ' ELSE '' END) ||
        (CASE WHEN thin_competition THEN 'Won against only ' || offers_received || ' offer' || (CASE WHEN offers_received = 1 THEN '' ELSE 's' END) || '. ' ELSE '' END) ||
        (CASE WHEN vehicle_holders_only THEN 'Order under ' || vehicle || ' - only its holders can bid.' ELSE 'Open-market contract.' END)) AS why_this_one,
      your_fit, your_size_check, score, award_url, source
    FROM scored
    ORDER BY rank
  8. 08SUMMARY - what your recompete list is hiding
    WITH d AS (SELECT * FROM input_1), t AS (SELECT * FROM input_2), you AS (SELECT * FROM input_3 LIMIT 1),
    lane AS (SELECT ANY_VALUE(naics_code) AS naics, ANY_VALUE(naics_description) AS industry, ANY_VALUE(awarding_agency) AS agency, ANY_VALUE(source) AS src FROM d),
    big AS (SELECT * FROM t WHERE incumbent_size_signal LIKE 'Federal awards alone%' ORDER BY annual_value DESC LIMIT 1),
    rows_out AS (
      SELECT 1 AS ord, 'THE LANE' AS area,
        (SELECT COUNT(*) FROM d) || ' largest contracts with a period ending in the next 18 months - ' || (SELECT lower(industry) || ' (' || naics || '), ' || agency FROM lane) AS finding,
        'None of this is private data - every row links to its award record. Source: ' || (SELECT src FROM lane) AS next_step
      UNION ALL
      SELECT 2, 'NOT REALLY ENDING',
        (SELECT COUNT(*) FILTER (WHERE NOT truly_ending) FROM d) || ' of ' || (SELECT COUNT(*) FROM d) || ' still have option years - the agency will most likely extend, and nothing is rebid',
        'Take them off the pipeline; the final end date is the one that matters'
      UNION ALL
      SELECT 3, 'REAL RECOMPETES',
        (SELECT COUNT(*) FROM t) || ' contracts worth about $' || (SELECT CAST(ROUND(SUM(annual_value) / 1e6, 0) AS BIGINT) FROM t) || 'M a year reach their FINAL end date in the window',
        'None needed - these are the ones worth capture time; see the ranked target list'
      UNION ALL
      SELECT 4, 'INCUMBENT MAY HAVE OUTGROWN THE SET-ASIDE',
        (SELECT COUNT(*) FROM t WHERE incumbent_size_signal LIKE 'Federal awards alone%') || ' of ' || (SELECT COUNT(*) FROM t WHERE set_aside <> '') || ' set-aside contracts: the incumbent group''s federal awards alone average more than the $' ||
          COALESCE((SELECT CAST(size_limit_usd_millions AS VARCHAR) FROM big), '?') || 'M small-business limit' ||
          COALESCE((SELECT ' - largest is award ' || award_id || ', about $' || ROUND(annual_value / 1e6, 1) || 'M a year' FROM big), ''),
        'A signal, not a ruling - verify size in SAM.gov; joint ventures and tribally owned firms can be exempt'
      UNION ALL
      SELECT 5, 'WHO THE INCUMBENT REALLY IS',
        'Incumbents listed under a different parent company: ' || (SELECT COUNT(*) FROM t WHERE why_this_one LIKE '%lists its parent as%'),
        'Size is judged with affiliates - read the parent column before you plan a challenge'
      UNION ALL
      SELECT 6, 'THIN COMPETITION LAST TIME',
        (SELECT COUNT(*) FROM t WHERE offers_received BETWEEN 1 AND 2) || ' were won against only one or two offers',
        'Fewer bidders last time usually means a beatable field - or a wired requirement; read the award record'
      UNION ALL
      SELECT 7, 'WHO CAN BID',
        (SELECT COUNT(*) FROM t WHERE vehicle <> '') || ' are orders under an existing contract vehicle; open-market contracts: ' || (SELECT COUNT(*) FROM t WHERE vehicle = ''),
        'Only a vehicle''s holders can bid on its orders - team with a holder, or go after the open-market ones'
      UNION ALL
      SELECT 8, 'YOUR SIZE',
        (SELECT 'Revenue of $' || ROUND(your_revenue_12m / 1e6, 1) || 'M over the last ' || months_covered || ' months' FROM you) ||
          COALESCE((SELECT ' against a $' || MAX(size_limit_usd_millions) || 'M limit for this industry' FROM t), ''),
        (SELECT CASE WHEN your_revenue_12m <= COALESCE((SELECT MAX(size_limit_usd_millions) FROM t), 0) * 1e6 THEN 'None needed - you qualify as small for this lane on these books' ELSE 'Over the limit on these books - set-asides are out of reach; look at teaming' END FROM you)
      UNION ALL
      SELECT 9, 'WHAT YOU COULD CARRY',
        (SELECT COUNT(*) FILTER (WHERE your_fit LIKE 'Prime%') || ' targets are prime-size for you, ' || COUNT(*) FILTER (WHERE your_fit LIKE 'Stretch%') || ' are a stretch, ' || COUNT(*) FILTER (WHERE your_fit LIKE 'Team%') || ' need a teaming partner' FROM t),
        'Sized against your own revenue - a contract worth more than twice your revenue a year is rarely winnable alone'
      UNION ALL
      SELECT 99, 'VERDICT',
        (SELECT COUNT(*) FROM t) || ' real recompetes - ' || (SELECT COUNT(*) FROM t WHERE incumbent_size_signal LIKE 'Federal awards alone%') || ' where the incumbent may be too big to rebid as small',
        'Start with the ranked target list'
    )
    SELECT ord, area, finding, next_step FROM rows_out ORDER BY ord

Run this on your books

Free to try — no sign-up, no card. The workflow runs in your browser; your data never leaves your machine.

Make it your own →